Changeset 6127 in josm for trunk/src/com/drew/metadata


Ignore:
Timestamp:
2013-08-09T18:05:11+02:00 (7 years ago)
Author:
bastiK
Message:

applied #8895 - Upgrade metadata-extractor to v. 2.6.4 (patch by ebourg)

Location:
trunk/src/com/drew/metadata
Files:
14 added
7 deleted
45 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/com/drew/metadata/DefaultTagDescriptor.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 22-Nov-2002 16:45:19 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata;
    1822
     23import com.drew.lang.annotations.NotNull;
     24
    1925/**
     26 * A default implementation of the abstract TagDescriptor.  As this class is not coded with awareness of any metadata
     27 * tags, it simply reports tag names using the format 'Unknown tag 0x00' (with the corresponding tag number in hex)
     28 * and gives descriptions using the default string representation of the value.
    2029 *
     30 * @author Drew Noakes http://drewnoakes.com
    2131 */
    22 public class DefaultTagDescriptor extends TagDescriptor
     32public class DefaultTagDescriptor extends TagDescriptor<Directory>
    2333{
    24     public DefaultTagDescriptor(Directory directory)
     34    public DefaultTagDescriptor(@NotNull Directory directory)
    2535    {
    2636        super(directory);
    2737    }
    2838
     39    /**
     40     * Gets a best-effort tag name using the format 'Unknown tag 0x00' (with the corresponding tag type in hex).
     41     * @param tagType the tag type identifier.
     42     * @return a string representation of the tag name.
     43     */
     44    @NotNull
    2945    public String getTagName(int tagType)
    3046    {
     
    3349        return "Unknown tag 0x" + hex;
    3450    }
    35 
    36     public String getDescription(int tagType)
    37     {
    38         return _directory.getString(tagType);
    39     }
    4051}
  • trunk/src/com/drew/metadata/Directory.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 25-Nov-2002 20:30:39 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata;
    1822
    1923import com.drew.lang.Rational;
    20 
    21 import java.io.Serializable;
     24import com.drew.lang.annotations.NotNull;
     25import com.drew.lang.annotations.Nullable;
     26import com.drew.lang.annotations.SuppressWarnings;
     27
     28import java.io.UnsupportedEncodingException;
    2229import java.lang.reflect.Array;
    2330import java.text.DateFormat;
    24 import java.util.ArrayList;
    25 import java.util.HashMap;
    26 import java.util.Iterator;
    27 import java.util.List;
     31import java.text.ParseException;
     32import java.text.SimpleDateFormat;
     33import java.util.*;
    2834
    2935/**
    30  * Base class for all Metadata directory types with supporting methods for setting and
    31  * getting tag values.
     36 * Abstract base class for all directory implementations, having methods for getting and setting tag values of various
     37 * data types.
     38 *
     39 * @author Drew Noakes http://drewnoakes.com
    3240 */
    33 public abstract class Directory implements Serializable
     41public abstract class Directory
    3442{
    35     /**
    36      * Map of values hashed by type identifiers.
    37      */
    38     protected final HashMap _tagMap;
    39 
    40     /**
    41      * The descriptor used to interperet tag values.
    42      */
    43     protected TagDescriptor _descriptor;
     43    // TODO get Array methods need to return cloned data, to maintain this directory's integrity
     44
     45    /** Map of values hashed by type identifiers. */
     46    @NotNull
     47    protected final Map<Integer, Object> _tagMap = new HashMap<Integer, Object>();
    4448
    4549    /**
     
    4852     * defined tags.
    4953     */
    50     protected final List _definedTagList;
    51 
    52     private List _errorList;
     54    @NotNull
     55    protected final Collection<Tag> _definedTagList = new ArrayList<Tag>();
     56
     57    @NotNull
     58    private final Collection<String> _errorList = new ArrayList<String>(4);
     59
     60    /** The descriptor used to interpret tag values. */
     61    protected TagDescriptor _descriptor;
    5362
    5463// ABSTRACT METHODS
     
    5665    /**
    5766     * Provides the name of the directory, for display purposes.  E.g. <code>Exif</code>
     67     *
    5868     * @return the name of the directory
    5969     */
     70    @NotNull
    6071    public abstract String getName();
    6172
    6273    /**
    6374     * Provides the map of tag names, hashed by tag type identifier.
     75     *
    6476     * @return the map of tag names
    6577     */
    66     protected abstract HashMap getTagNameMap();
    67 
    68 // CONSTRUCTORS
    69 
    70     /**
    71      * Creates a new Directory.
    72      */
    73     public Directory()
    74     {
    75         _tagMap = new HashMap();
    76         _definedTagList = new ArrayList();
    77     }
     78    @NotNull
     79    protected abstract HashMap<Integer, String> getTagNameMap();
     80
     81    protected Directory()
     82    {}
    7883
    7984// VARIOUS METHODS
     
    8186    /**
    8287     * Indicates whether the specified tag type has been set.
     88     *
    8389     * @param tagType the tag type to check for
    8490     * @return true if a value exists for the specified tag type, false if not
    8591     */
     92    @java.lang.SuppressWarnings({ "UnnecessaryBoxing" })
    8693    public boolean containsTag(int tagType)
    8794    {
    88         return _tagMap.containsKey(new Integer(tagType));
     95        return _tagMap.containsKey(Integer.valueOf(tagType));
    8996    }
    9097
    9198    /**
    9299     * Returns an Iterator of Tag instances that have been set in this Directory.
     100     *
    93101     * @return an Iterator of Tag instances
    94102     */
    95     public Iterator getTagIterator()
    96     {
    97         return _definedTagList.iterator();
     103    @NotNull
     104    public Collection<Tag> getTags()
     105    {
     106        return _definedTagList;
    98107    }
    99108
    100109    /**
    101110     * Returns the number of tags set in this Directory.
     111     *
    102112     * @return the number of tags set in this Directory
    103113     */
     
    108118
    109119    /**
    110      * Sets the descriptor used to interperet tag values.
    111      * @param descriptor the descriptor used to interperet tag values
    112      */
    113     public void setDescriptor(TagDescriptor descriptor)
    114     {
    115         if (descriptor==null) {
     120     * Sets the descriptor used to interpret tag values.
     121     *
     122     * @param descriptor the descriptor used to interpret tag values
     123     */
     124    @java.lang.SuppressWarnings({ "ConstantConditions" })
     125    public void setDescriptor(@NotNull TagDescriptor descriptor)
     126    {
     127        if (descriptor == null)
    116128            throw new NullPointerException("cannot set a null descriptor");
    117         }
    118129        _descriptor = descriptor;
    119130    }
    120131
    121     public void addError(String message)
    122     {
    123         if (_errorList==null) {
    124             _errorList = new ArrayList();
    125         }
     132    /**
     133     * Registers an error message with this directory.
     134     *
     135     * @param message an error message.
     136     */
     137    public void addError(@NotNull String message)
     138    {
    126139        _errorList.add(message);
    127140    }
    128141
     142    /**
     143     * Gets a value indicating whether this directory has any error messages.
     144     *
     145     * @return true if the directory contains errors, otherwise false
     146     */
    129147    public boolean hasErrors()
    130148    {
    131         return (_errorList!=null && _errorList.size()>0);
    132     }
    133 
    134     public Iterator getErrors()
    135     {
    136         return _errorList.iterator();
    137     }
    138 
     149        return _errorList.size() > 0;
     150    }
     151
     152    /**
     153     * Used to iterate over any error messages contained in this directory.
     154     *
     155     * @return an iterable collection of error message strings.
     156     */
     157    @NotNull
     158    public Iterable<String> getErrors()
     159    {
     160        return _errorList;
     161    }
     162
     163    /** Returns the count of error messages in this directory. */
    139164    public int getErrorCount()
    140165    {
     
    145170
    146171    /**
    147      * Sets an int value for the specified tag.
     172     * Sets an <code>int</code> value for the specified tag.
     173     *
    148174     * @param tagType the tag's value as an int
    149      * @param value the value for the specified tag as an int
     175     * @param value   the value for the specified tag as an int
    150176     */
    151177    public void setInt(int tagType, int value)
    152178    {
    153         setObject(tagType, new Integer(value));
    154     }
    155 
    156     /**
    157      * Sets a double value for the specified tag.
     179        setObject(tagType, value);
     180    }
     181
     182    /**
     183     * Sets an <code>int[]</code> (array) for the specified tag.
     184     *
     185     * @param tagType the tag identifier
     186     * @param ints    the int array to store
     187     */
     188    public void setIntArray(int tagType, @NotNull int[] ints)
     189    {
     190        setObjectArray(tagType, ints);
     191    }
     192
     193    /**
     194     * Sets a <code>float</code> value for the specified tag.
     195     *
    158196     * @param tagType the tag's value as an int
    159      * @param value the value for the specified tag as a double
     197     * @param value   the value for the specified tag as a float
     198     */
     199    public void setFloat(int tagType, float value)
     200    {
     201        setObject(tagType, value);
     202    }
     203
     204    /**
     205     * Sets a <code>float[]</code> (array) for the specified tag.
     206     *
     207     * @param tagType the tag identifier
     208     * @param floats  the float array to store
     209     */
     210    public void setFloatArray(int tagType, @NotNull float[] floats)
     211    {
     212        setObjectArray(tagType, floats);
     213    }
     214
     215    /**
     216     * Sets a <code>double</code> value for the specified tag.
     217     *
     218     * @param tagType the tag's value as an int
     219     * @param value   the value for the specified tag as a double
    160220     */
    161221    public void setDouble(int tagType, double value)
    162222    {
    163         setObject(tagType, new Double(value));
    164     }
    165 
    166     /**
    167      * Sets a float value for the specified tag.
     223        setObject(tagType, value);
     224    }
     225
     226    /**
     227     * Sets a <code>double[]</code> (array) for the specified tag.
     228     *
     229     * @param tagType the tag identifier
     230     * @param doubles the double array to store
     231     */
     232    public void setDoubleArray(int tagType, @NotNull double[] doubles)
     233    {
     234        setObjectArray(tagType, doubles);
     235    }
     236
     237    /**
     238     * Sets a <code>String</code> value for the specified tag.
     239     *
    168240     * @param tagType the tag's value as an int
    169      * @param value the value for the specified tag as a float
    170      */
    171     public void setFloat(int tagType, float value)
    172     {
    173         setObject(tagType, new Float(value));
    174     }
    175 
    176     /**
    177      * Sets an int value for the specified tag.
    178      * @param tagType the tag's value as an int
    179      * @param value the value for the specified tag as a String
    180      */
    181     public void setString(int tagType, String value)
    182     {
     241     * @param value   the value for the specified tag as a String
     242     */
     243    @java.lang.SuppressWarnings({ "ConstantConditions" })
     244    public void setString(int tagType, @NotNull String value)
     245    {
     246        if (value == null)
     247            throw new NullPointerException("cannot set a null String");
    183248        setObject(tagType, value);
    184249    }
    185250
    186251    /**
    187      * Sets an int value for the specified tag.
    188      * @param tagType the tag's value as an int
    189      * @param value the value for the specified tag as a boolean
    190      */
    191     public void setBoolean(int tagType, boolean value)
    192     {
    193         setObject(tagType, new Boolean(value));
    194     }
    195 
    196     /**
    197      * Sets a long value for the specified tag.
    198      * @param tagType the tag's value as an int
    199      * @param value the value for the specified tag as a long
    200      */
    201     public void setLong(int tagType, long value)
    202     {
    203         setObject(tagType, new Long(value));
    204     }
    205 
    206     /**
    207      * Sets a java.util.Date value for the specified tag.
    208      * @param tagType the tag's value as an int
    209      * @param value the value for the specified tag as a java.util.Date
    210      */
    211     public void setDate(int tagType, java.util.Date value)
    212     {
    213         setObject(tagType, value);
    214     }
    215 
    216     /**
    217      * Sets a Rational value for the specified tag.
    218      * @param tagType the tag's value as an int
    219      * @param rational rational number
    220      */
    221     public void setRational(int tagType, Rational rational)
    222     {
    223         setObject(tagType, rational);
    224     }
    225 
    226     /**
    227      * Sets a Rational array for the specified tag.
    228      * @param tagType the tag identifier
    229      * @param rationals the Rational array to store
    230      */
    231     public void setRationalArray(int tagType, Rational[] rationals)
    232     {
    233         setObjectArray(tagType, rationals);
    234     }
    235 
    236     /**
    237      * Sets an int array for the specified tag.
    238      * @param tagType the tag identifier
    239      * @param ints the int array to store
    240      */
    241     public void setIntArray(int tagType, int[] ints)
    242     {
    243         setObjectArray(tagType, ints);
    244     }
    245 
    246     /**
    247      * Sets a byte array for the specified tag.
    248      * @param tagType the tag identifier
    249      * @param bytes the byte array to store
    250      */
    251     public void setByteArray(int tagType, byte[] bytes)
    252     {
    253         setObjectArray(tagType, bytes);
    254     }
    255 
    256     /**
    257      * Sets a String array for the specified tag.
     252     * Sets a <code>String[]</code> (array) for the specified tag.
     253     *
    258254     * @param tagType the tag identifier
    259255     * @param strings the String array to store
    260256     */
    261     public void setStringArray(int tagType, String[] strings)
     257    public void setStringArray(int tagType, @NotNull String[] strings)
    262258    {
    263259        setObjectArray(tagType, strings);
     
    265261
    266262    /**
    267      * Private helper method, containing common functionality for all 'add'
    268      * methods.
     263     * Sets a <code>boolean</code> value for the specified tag.
     264     *
    269265     * @param tagType the tag's value as an int
    270      * @param value the value for the specified tag
     266     * @param value   the value for the specified tag as a boolean
     267     */
     268    public void setBoolean(int tagType, boolean value)
     269    {
     270        setObject(tagType, value);
     271    }
     272
     273    /**
     274     * Sets a <code>long</code> value for the specified tag.
     275     *
     276     * @param tagType the tag's value as an int
     277     * @param value   the value for the specified tag as a long
     278     */
     279    public void setLong(int tagType, long value)
     280    {
     281        setObject(tagType, value);
     282    }
     283
     284    /**
     285     * Sets a <code>java.util.Date</code> value for the specified tag.
     286     *
     287     * @param tagType the tag's value as an int
     288     * @param value   the value for the specified tag as a java.util.Date
     289     */
     290    public void setDate(int tagType, @NotNull java.util.Date value)
     291    {
     292        setObject(tagType, value);
     293    }
     294
     295    /**
     296     * Sets a <code>Rational</code> value for the specified tag.
     297     *
     298     * @param tagType  the tag's value as an int
     299     * @param rational rational number
     300     */
     301    public void setRational(int tagType, @NotNull Rational rational)
     302    {
     303        setObject(tagType, rational);
     304    }
     305
     306    /**
     307     * Sets a <code>Rational[]</code> (array) for the specified tag.
     308     *
     309     * @param tagType   the tag identifier
     310     * @param rationals the Rational array to store
     311     */
     312    public void setRationalArray(int tagType, @NotNull Rational[] rationals)
     313    {
     314        setObjectArray(tagType, rationals);
     315    }
     316
     317    /**
     318     * Sets a <code>byte[]</code> (array) for the specified tag.
     319     *
     320     * @param tagType the tag identifier
     321     * @param bytes   the byte array to store
     322     */
     323    public void setByteArray(int tagType, @NotNull byte[] bytes)
     324    {
     325        setObjectArray(tagType, bytes);
     326    }
     327
     328    /**
     329     * Sets a <code>Object</code> for the specified tag.
     330     *
     331     * @param tagType the tag's value as an int
     332     * @param value   the value for the specified tag
    271333     * @throws NullPointerException if value is <code>null</code>
    272334     */
    273     public void setObject(int tagType, Object value)
    274     {
    275         if (value==null) {
     335    @java.lang.SuppressWarnings( { "ConstantConditions", "UnnecessaryBoxing" })
     336    public void setObject(int tagType, @NotNull Object value)
     337    {
     338        if (value == null)
    276339            throw new NullPointerException("cannot set a null object");
    277         }
    278 
    279         Integer key = new Integer(tagType);
    280         if (!_tagMap.containsKey(key)) {
     340
     341        if (!_tagMap.containsKey(Integer.valueOf(tagType))) {
    281342            _definedTagList.add(new Tag(tagType, this));
    282343        }
    283         _tagMap.put(key, value);
    284     }
    285 
    286     /**
    287      * Private helper method, containing common functionality for all 'add...Array'
    288      * methods.
     344//        else {
     345//            final Object oldValue = _tagMap.get(tagType);
     346//            if (!oldValue.equals(value))
     347//                addError(String.format("Overwritten tag 0x%s (%s).  Old=%s, New=%s", Integer.toHexString(tagType), getTagName(tagType), oldValue, value));
     348//        }
     349        _tagMap.put(tagType, value);
     350    }
     351
     352    /**
     353     * Sets an array <code>Object</code> for the specified tag.
     354     *
    289355     * @param tagType the tag's value as an int
    290      * @param array the array of values for the specified tag
    291      */
    292     public void setObjectArray(int tagType, Object array)
     356     * @param array   the array of values for the specified tag
     357     */
     358    public void setObjectArray(int tagType, @NotNull Object array)
    293359    {
    294360        // for now, we don't do anything special -- this method might be a candidate for removal once the dust settles
     
    299365
    300366    /**
    301      * Returns the specified tag's value as an int, if possible.
     367     * Returns the specified tag's value as an int, if possible.  Every attempt to represent the tag's value as an int
     368     * is taken.  Here is a list of the action taken depending upon the tag's original type:
     369     * <ul>
     370     * <li> int - Return unchanged.
     371     * <li> Number - Return an int value (real numbers are truncated).
     372     * <li> Rational - Truncate any fractional part and returns remaining int.
     373     * <li> String - Attempt to parse string as an int.  If this fails, convert the char[] to an int (using shifts and OR).
     374     * <li> Rational[] - Return int value of first item in array.
     375     * <li> byte[] - Return int value of first item in array.
     376     * <li> int[] - Return int value of first item in array.
     377     * </ul>
     378     *
     379     * @throws MetadataException if no value exists for tagType or if it cannot be converted to an int.
    302380     */
    303381    public int getInt(int tagType) throws MetadataException
    304382    {
    305         Object o = getObject(tagType);
    306         if (o==null) {
    307             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    308         } else if (o instanceof String) {
     383        Integer integer = getInteger(tagType);
     384        if (integer!=null)
     385            return integer;
     386
     387        Object o = getObject(tagType);
     388        if (o == null)
     389            throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first");
     390        throw new MetadataException("Tag '" + tagType + "' cannot be converted to int.  It is of type '" + o.getClass() + "'.");
     391    }
     392
     393    /**
     394     * Returns the specified tag's value as an Integer, if possible.  Every attempt to represent the tag's value as an
     395     * Integer is taken.  Here is a list of the action taken depending upon the tag's original type:
     396     * <ul>
     397     * <li> int - Return unchanged
     398     * <li> Number - Return an int value (real numbers are truncated)
     399     * <li> Rational - Truncate any fractional part and returns remaining int
     400     * <li> String - Attempt to parse string as an int.  If this fails, convert the char[] to an int (using shifts and OR)
     401     * <li> Rational[] - Return int value of first item in array if length &gt; 0
     402     * <li> byte[] - Return int value of first item in array if length &gt; 0
     403     * <li> int[] - Return int value of first item in array if length &gt; 0
     404     * </ul>
     405     *
     406     * If the value is not found or cannot be converted to int, <code>null</code> is returned.
     407     */
     408    @Nullable
     409    public Integer getInteger(int tagType)
     410    {
     411        Object o = getObject(tagType);
     412
     413        if (o == null)
     414            return null;
     415
     416        if (o instanceof String) {
    309417            try {
    310418                return Integer.parseInt((String)o);
     
    314422                byte[] bytes = s.getBytes();
    315423                long val = 0;
    316                 for (int i = 0; i < bytes.length; i++) {
     424                for (byte aByte : bytes) {
    317425                    val = val << 8;
    318                     val += bytes[i];
     426                    val += (aByte & 0xff);
    319427                }
    320428                return (int)val;
     
    324432        } else if (o instanceof Rational[]) {
    325433            Rational[] rationals = (Rational[])o;
    326             if (rationals.length==1)
     434            if (rationals.length == 1)
    327435                return rationals[0].intValue();
    328436        } else if (o instanceof byte[]) {
    329437            byte[] bytes = (byte[])o;
    330             if (bytes.length==1)
    331                 return bytes[0];
     438            if (bytes.length == 1)
     439                return (int)bytes[0];
    332440        } else if (o instanceof int[]) {
    333441            int[] ints = (int[])o;
    334             if (ints.length==1)
     442            if (ints.length == 1)
    335443                return ints[0];
    336444        }
    337         throw new MetadataException("Tag '" + tagType + "' cannot be cast to int.  It is of type '" + o.getClass() + "'.");
    338     }
    339 
    340     // TODO get Array methods need to return cloned data, to maintain this directory's integrity
     445        return null;
     446    }
    341447
    342448    /**
    343449     * Gets the specified tag's value as a String array, if possible.  Only supported
    344450     * where the tag is set as String[], String, int[], byte[] or Rational[].
     451     *
    345452     * @param tagType the tag identifier
    346      * @return the tag's value as an array of Strings
    347      * @throws MetadataException if the tag has not been set or cannot be represented
    348      *         as a String[]
    349      */
    350     public String[] getStringArray(int tagType) throws MetadataException
    351     {
    352         Object o = getObject(tagType);
    353         if (o==null) {
    354             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    355         } else if (o instanceof String[]) {
     453     * @return the tag's value as an array of Strings. If the value is unset or cannot be converted, <code>null</code> is returned.
     454     */
     455    @Nullable
     456    public String[] getStringArray(int tagType)
     457    {
     458        Object o = getObject(tagType);
     459        if (o == null)
     460            return null;
     461        if (o instanceof String[])
    356462            return (String[])o;
    357         } else if (o instanceof String) {
    358             String[] strings = {(String)o};
    359             return strings;
    360         } else if (o instanceof int[]) {
     463        if (o instanceof String)
     464            return new String[] { (String)o };
     465        if (o instanceof int[]) {
    361466            int[] ints = (int[])o;
    362467            String[] strings = new String[ints.length];
    363             for (int i = 0; i<strings.length; i++) {
     468            for (int i = 0; i < strings.length; i++)
    364469                strings[i] = Integer.toString(ints[i]);
    365             }
    366470            return strings;
    367471        } else if (o instanceof byte[]) {
    368472            byte[] bytes = (byte[])o;
    369473            String[] strings = new String[bytes.length];
    370             for (int i = 0; i<strings.length; i++) {
     474            for (int i = 0; i < strings.length; i++)
    371475                strings[i] = Byte.toString(bytes[i]);
    372             }
    373476            return strings;
    374477        } else if (o instanceof Rational[]) {
    375478            Rational[] rationals = (Rational[])o;
    376479            String[] strings = new String[rationals.length];
    377             for (int i = 0; i<strings.length; i++) {
     480            for (int i = 0; i < strings.length; i++)
    378481                strings[i] = rationals[i].toSimpleString(false);
    379             }
    380482            return strings;
    381483        }
    382         throw new MetadataException("Tag '" + tagType + "' cannot be cast to an String array.  It is of type '" + o.getClass() + "'.");
     484        return null;
    383485    }
    384486
    385487    /**
    386488     * Gets the specified tag's value as an int array, if possible.  Only supported
    387      * where the tag is set as String, int[], byte[] or Rational[].
     489     * where the tag is set as String, Integer, int[], byte[] or Rational[].
     490     *
    388491     * @param tagType the tag identifier
    389492     * @return the tag's value as an int array
    390      * @throws MetadataException if the tag has not been set, or cannot be converted to
    391      *         an int array
    392      */
    393     public int[] getIntArray(int tagType) throws MetadataException
    394     {
    395         Object o = getObject(tagType);
    396         if (o==null) {
    397             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    398         } else if (o instanceof Rational[]) {
     493     */
     494    @Nullable
     495    public int[] getIntArray(int tagType)
     496    {
     497        Object o = getObject(tagType);
     498        if (o == null)
     499            return null;
     500        if (o instanceof Rational[]) {
    399501            Rational[] rationals = (Rational[])o;
    400502            int[] ints = new int[rationals.length];
    401             for (int i = 0; i<ints.length; i++) {
     503            for (int i = 0; i < ints.length; i++) {
    402504                ints[i] = rationals[i].intValue();
    403505            }
    404506            return ints;
    405         } else if (o instanceof int[]) {
     507        }
     508        if (o instanceof int[])
    406509            return (int[])o;
    407         } else if (o instanceof byte[]) {
     510        if (o instanceof byte[]) {
    408511            byte[] bytes = (byte[])o;
    409512            int[] ints = new int[bytes.length];
    410             for (int i = 0; i<bytes.length; i++) {
     513            for (int i = 0; i < bytes.length; i++) {
    411514                byte b = bytes[i];
    412515                ints[i] = b;
    413516            }
    414517            return ints;
    415         } else if (o instanceof String) {
    416             String str = (String)o;
     518        }
     519        if (o instanceof CharSequence) {
     520            CharSequence str = (CharSequence)o;
    417521            int[] ints = new int[str.length()];
    418             for (int i = 0; i<str.length(); i++) {
     522            for (int i = 0; i < str.length(); i++) {
    419523                ints[i] = str.charAt(i);
    420524            }
    421525            return ints;
    422526        }
    423         throw new MetadataException("Tag '" + tagType + "' cannot be cast to an int array.  It is of type '" + o.getClass() + "'.");
     527        if (o instanceof Integer)
     528            return new int[] { (Integer)o };
     529       
     530        return null;
    424531    }
    425532
    426533    /**
    427534     * Gets the specified tag's value as an byte array, if possible.  Only supported
    428      * where the tag is set as String, int[], byte[] or Rational[].
     535     * where the tag is set as String, Integer, int[], byte[] or Rational[].
     536     *
    429537     * @param tagType the tag identifier
    430538     * @return the tag's value as a byte array
    431      * @throws MetadataException if the tag has not been set, or cannot be converted to
    432      *         a byte array
    433      */
    434     public byte[] getByteArray(int tagType) throws MetadataException
    435     {
    436         Object o = getObject(tagType);
    437         if (o==null) {
    438             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
     539     */
     540    @Nullable
     541    public byte[] getByteArray(int tagType)
     542    {
     543        Object o = getObject(tagType);
     544        if (o == null) {
     545            return null;
    439546        } else if (o instanceof Rational[]) {
    440547            Rational[] rationals = (Rational[])o;
    441548            byte[] bytes = new byte[rationals.length];
    442             for (int i = 0; i<bytes.length; i++) {
     549            for (int i = 0; i < bytes.length; i++) {
    443550                bytes[i] = rationals[i].byteValue();
    444551            }
     
    449556            int[] ints = (int[])o;
    450557            byte[] bytes = new byte[ints.length];
    451             for (int i = 0; i<ints.length; i++) {
     558            for (int i = 0; i < ints.length; i++) {
    452559                bytes[i] = (byte)ints[i];
    453560            }
    454561            return bytes;
    455         } else if (o instanceof String) {
    456             String str = (String)o;
     562        } else if (o instanceof CharSequence) {
     563            CharSequence str = (CharSequence)o;
    457564            byte[] bytes = new byte[str.length()];
    458             for (int i = 0; i<str.length(); i++) {
     565            for (int i = 0; i < str.length(); i++) {
    459566                bytes[i] = (byte)str.charAt(i);
    460567            }
    461568            return bytes;
    462569        }
    463         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a byte array.  It is of type '" + o.getClass() + "'.");
    464     }
    465 
    466     /**
    467      * Returns the specified tag's value as a double, if possible.
    468      */
     570        if (o instanceof Integer)
     571            return new byte[] { ((Integer)o).byteValue() };
     572
     573        return null;
     574    }
     575
     576    /** Returns the specified tag's value as a double, if possible. */
    469577    public double getDouble(int tagType) throws MetadataException
    470578    {
    471         Object o = getObject(tagType);
    472         if (o==null) {
    473             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    474         } else if (o instanceof String) {
     579        Double value = getDoubleObject(tagType);
     580        if (value!=null)
     581            return value;
     582        Object o = getObject(tagType);
     583        if (o == null)
     584            throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first");
     585        throw new MetadataException("Tag '" + tagType + "' cannot be converted to a double.  It is of type '" + o.getClass() + "'.");
     586    }
     587    /** Returns the specified tag's value as a Double.  If the tag is not set or cannot be converted, <code>null</code> is returned. */
     588    @Nullable
     589    public Double getDoubleObject(int tagType)
     590    {
     591        Object o = getObject(tagType);
     592        if (o == null)
     593            return null;
     594        if (o instanceof String) {
    475595            try {
    476596                return Double.parseDouble((String)o);
    477597            } catch (NumberFormatException nfe) {
    478                 throw new MetadataException("unable to parse string " + o + " as a double", nfe);
    479             }
    480         } else if (o instanceof Number) {
     598                return null;
     599            }
     600        }
     601        if (o instanceof Number)
    481602            return ((Number)o).doubleValue();
    482         }
    483         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a double.  It is of type '" + o.getClass() + "'.");
    484     }
    485 
    486     /**
    487      * Returns the specified tag's value as a float, if possible.
    488      */
     603
     604        return null;
     605    }
     606
     607    /** Returns the specified tag's value as a float, if possible. */
    489608    public float getFloat(int tagType) throws MetadataException
    490609    {
    491         Object o = getObject(tagType);
    492         if (o==null) {
    493             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    494         } else if (o instanceof String) {
     610        Float value = getFloatObject(tagType);
     611        if (value!=null)
     612            return value;
     613        Object o = getObject(tagType);
     614        if (o == null)
     615            throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first");
     616        throw new MetadataException("Tag '" + tagType + "' cannot be converted to a float.  It is of type '" + o.getClass() + "'.");
     617    }
     618
     619    /** Returns the specified tag's value as a float.  If the tag is not set or cannot be converted, <code>null</code> is returned. */
     620    @Nullable
     621    public Float getFloatObject(int tagType)
     622    {
     623        Object o = getObject(tagType);
     624        if (o == null)
     625            return null;
     626        if (o instanceof String) {
    495627            try {
    496628                return Float.parseFloat((String)o);
    497629            } catch (NumberFormatException nfe) {
    498                 throw new MetadataException("unable to parse string " + o + " as a float", nfe);
    499             }
    500         } else if (o instanceof Number) {
     630                return null;
     631            }
     632        }
     633        if (o instanceof Number)
    501634            return ((Number)o).floatValue();
    502         }
    503         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a float.  It is of type '" + o.getClass() + "'.");
    504     }
    505 
    506     /**
    507      * Returns the specified tag's value as a long, if possible.
    508      */
     635        return null;
     636    }
     637
     638    /** Returns the specified tag's value as a long, if possible. */
    509639    public long getLong(int tagType) throws MetadataException
    510640    {
    511         Object o = getObject(tagType);
    512         if (o==null) {
    513             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    514         } else if (o instanceof String) {
     641        Long value = getLongObject(tagType);
     642        if (value!=null)
     643            return value;
     644        Object o = getObject(tagType);
     645        if (o == null)
     646            throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first");
     647        throw new MetadataException("Tag '" + tagType + "' cannot be converted to a long.  It is of type '" + o.getClass() + "'.");
     648    }
     649
     650    /** Returns the specified tag's value as a long.  If the tag is not set or cannot be converted, <code>null</code> is returned. */
     651    @Nullable
     652    public Long getLongObject(int tagType)
     653    {
     654        Object o = getObject(tagType);
     655        if (o == null)
     656            return null;
     657        if (o instanceof String) {
    515658            try {
    516659                return Long.parseLong((String)o);
    517660            } catch (NumberFormatException nfe) {
    518                 throw new MetadataException("unable to parse string " + o + " as a long", nfe);
    519             }
    520         } else if (o instanceof Number) {
     661                return null;
     662            }
     663        }
     664        if (o instanceof Number)
    521665            return ((Number)o).longValue();
    522         }
    523         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a long.  It is of type '" + o.getClass() + "'.");
    524     }
    525 
    526     /**
    527      * Returns the specified tag's value as a boolean, if possible.
    528      */
     666        return null;
     667    }
     668
     669    /** Returns the specified tag's value as a boolean, if possible. */
    529670    public boolean getBoolean(int tagType) throws MetadataException
    530671    {
    531         Object o = getObject(tagType);
    532         if (o==null) {
    533             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    534         } else if (o instanceof Boolean) {
    535             return ((Boolean)o).booleanValue();
    536         } else if (o instanceof String) {
     672        Boolean value = getBooleanObject(tagType);
     673        if (value!=null)
     674            return value;
     675        Object o = getObject(tagType);
     676        if (o == null)
     677            throw new MetadataException("Tag '" + getTagName(tagType) + "' has not been set -- check using containsTag() first");
     678        throw new MetadataException("Tag '" + tagType + "' cannot be converted to a boolean.  It is of type '" + o.getClass() + "'.");
     679    }
     680
     681    /** Returns the specified tag's value as a boolean.  If the tag is not set or cannot be converted, <code>null</code> is returned. */
     682    @Nullable
     683    @SuppressWarnings(value = "NP_BOOLEAN_RETURN_NULL", justification = "keep API interface consistent")
     684    public Boolean getBooleanObject(int tagType)
     685    {
     686        Object o = getObject(tagType);
     687        if (o == null)
     688            return null;
     689        if (o instanceof Boolean)
     690            return (Boolean)o;
     691        if (o instanceof String) {
    537692            try {
    538693                return Boolean.getBoolean((String)o);
    539694            } catch (NumberFormatException nfe) {
    540                 throw new MetadataException("unable to parse string " + o + " as a boolean", nfe);
    541             }
    542         } else if (o instanceof Number) {
    543             return (((Number)o).doubleValue()!=0);
    544         }
    545         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a boolean.  It is of type '" + o.getClass() + "'.");
    546     }
    547 
    548     /**
    549      * Returns the specified tag's value as a java.util.Date, if possible.
    550      */
    551     public java.util.Date getDate(int tagType) throws MetadataException
    552     {
    553         Object o = getObject(tagType);
    554         if (o==null) {
    555             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    556         } else if (o instanceof java.util.Date) {
     695                return null;
     696            }
     697        }
     698        if (o instanceof Number)
     699            return (((Number)o).doubleValue() != 0);
     700        return null;
     701    }
     702
     703    /**
     704     * Returns the specified tag's value as a java.util.Date.  If the value is unset or cannot be converted, <code>null</code> is returned.
     705     * <p/>
     706     * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
     707     * the current {@link TimeZone}.  If the {@link TimeZone} is known, call the overload that accepts one as an argument.
     708     */
     709    @Nullable
     710    public java.util.Date getDate(int tagType)
     711    {
     712        return getDate(tagType, null);
     713    }
     714   
     715    /**
     716     * Returns the specified tag's value as a java.util.Date.  If the value is unset or cannot be converted, <code>null</code> is returned.
     717     * <p/>
     718     * If the underlying value is a {@link String}, then attempts will be made to parse the string as though it is in
     719     * the {@link TimeZone} represented by the {@code timeZone} parameter (if it is non-null).  Note that this parameter
     720     * is only considered if the underlying value is a string and parsing occurs, otherwise it has no effect.
     721     */
     722    @Nullable
     723    public java.util.Date getDate(int tagType, @Nullable TimeZone timeZone)
     724    {
     725        Object o = getObject(tagType);
     726
     727        if (o == null)
     728            return null;
     729
     730        if (o instanceof java.util.Date)
    557731            return (java.util.Date)o;
    558         } else if (o instanceof String) {
    559             // add new dateformat strings to make this method even smarter
    560             // so far, this seems to cover all known date strings
    561             // (for example, AM and PM strings are not supported...)
     732
     733        if (o instanceof String) {
     734            // This seems to cover all known Exif date strings
     735            // Note that "    :  :     :  :  " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html
    562736            String datePatterns[] = {
    563                 "yyyy:MM:dd HH:mm:ss",
    564                 "yyyy:MM:dd HH:mm",
    565                 "yyyy-MM-dd HH:mm:ss",
    566                 "yyyy-MM-dd HH:mm"};
     737                    "yyyy:MM:dd HH:mm:ss",
     738                    "yyyy:MM:dd HH:mm",
     739                    "yyyy-MM-dd HH:mm:ss",
     740                    "yyyy-MM-dd HH:mm",
     741                    "yyyy.MM.dd HH:mm:ss",
     742                    "yyyy.MM.dd HH:mm" };
    567743            String dateString = (String)o;
    568             for (int i = 0; i<datePatterns.length; i++) {
     744            for (String datePattern : datePatterns) {
    569745                try {
    570                     DateFormat parser = new java.text.SimpleDateFormat(datePatterns[i]);
     746                    DateFormat parser = new SimpleDateFormat(datePattern);
     747                    if (timeZone != null)
     748                        parser.setTimeZone(timeZone);
    571749                    return parser.parse(dateString);
    572                 } catch (java.text.ParseException ex) {
     750                } catch (ParseException ex) {
    573751                    // simply try the next pattern
    574752                }
    575753            }
    576754        }
    577         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a java.util.Date.  It is of type '" + o.getClass() + "'.");
    578     }
    579 
    580     /**
    581      * Returns the specified tag's value as a Rational, if possible.
    582      */
    583     public Rational getRational(int tagType) throws MetadataException
    584     {
    585         Object o = getObject(tagType);
    586         if (o==null) {
    587             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    588         } else if (o instanceof Rational) {
     755        return null;
     756    }
     757
     758    /** Returns the specified tag's value as a Rational.  If the value is unset or cannot be converted, <code>null</code> is returned. */
     759    @Nullable
     760    public Rational getRational(int tagType)
     761    {
     762        Object o = getObject(tagType);
     763
     764        if (o == null)
     765            return null;
     766
     767        if (o instanceof Rational)
    589768            return (Rational)o;
    590         }
    591         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational.  It is of type '" + o.getClass() + "'.");
    592     }
    593 
    594     public Rational[] getRationalArray(int tagType) throws MetadataException
    595     {
    596         Object o = getObject(tagType);
    597         if (o==null) {
    598             throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
    599         } else if (o instanceof Rational[]) {
     769        if (o instanceof Integer)
     770            return new Rational((Integer)o, 1);
     771        if (o instanceof Long)
     772            return new Rational((Long)o, 1);
     773
     774        // NOTE not doing conversions for real number types
     775
     776        return null;
     777    }
     778
     779    /** Returns the specified tag's value as an array of Rational.  If the value is unset or cannot be converted, <code>null</code> is returned. */
     780    @Nullable
     781    public Rational[] getRationalArray(int tagType)
     782    {
     783        Object o = getObject(tagType);
     784        if (o == null)
     785            return null;
     786
     787        if (o instanceof Rational[])
    600788            return (Rational[])o;
    601         }
    602         throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational array.  It is of type '" + o.getClass() + "'.");
     789
     790        return null;
    603791    }
    604792
     
    606794     * Returns the specified tag's value as a String.  This value is the 'raw' value.  A more presentable decoding
    607795     * of this value may be obtained from the corresponding Descriptor.
    608      * @return the String reprensentation of the tag's value, or
     796     *
     797     * @return the String representation of the tag's value, or
    609798     *         <code>null</code> if the tag hasn't been defined.
    610799     */
     800    @Nullable
    611801    public String getString(int tagType)
    612802    {
    613803        Object o = getObject(tagType);
    614         if (o==null)
     804        if (o == null)
    615805            return null;
    616806
     
    618808            return ((Rational)o).toSimpleString(true);
    619809
    620         if (o.getClass().isArray())
    621         {
     810        if (o.getClass().isArray()) {
    622811            // handle arrays of objects and primitives
    623812            int arrayLength = Array.getLength(o);
    624             // determine if this is an array of objects i.e. [Lcom.drew.blah
    625             boolean isObjectArray = o.getClass().toString().startsWith("class [L");
    626             StringBuffer sbuffer = new StringBuffer();
    627             for (int i = 0; i<arrayLength; i++)
    628             {
    629                 if (i!=0)
    630                     sbuffer.append(' ');
     813            final Class<?> componentType = o.getClass().getComponentType();
     814            boolean isObjectArray = Object.class.isAssignableFrom(componentType);
     815            boolean isFloatArray = componentType.getName().equals("float");
     816            boolean isDoubleArray = componentType.getName().equals("double");
     817            boolean isIntArray = componentType.getName().equals("int");
     818            boolean isLongArray = componentType.getName().equals("long");
     819            boolean isByteArray = componentType.getName().equals("byte");
     820            StringBuilder string = new StringBuilder();
     821            for (int i = 0; i < arrayLength; i++) {
     822                if (i != 0)
     823                    string.append(' ');
    631824                if (isObjectArray)
    632                     sbuffer.append(Array.get(o, i).toString());
     825                    string.append(Array.get(o, i).toString());
     826                else if (isIntArray)
     827                    string.append(Array.getInt(o, i));
     828                else if (isLongArray)
     829                    string.append(Array.getLong(o, i));
     830                else if (isFloatArray)
     831                    string.append(Array.getFloat(o, i));
     832                else if (isDoubleArray)
     833                    string.append(Array.getDouble(o, i));
     834                else if (isByteArray)
     835                    string.append(Array.getByte(o, i));
    633836                else
    634                     sbuffer.append(Array.getInt(o, i));
    635             }
    636             return sbuffer.toString();
    637         }
    638 
     837                    addError("Unexpected array component type: " + componentType.getName());
     838            }
     839            return string.toString();
     840        }
     841
     842        // Note that several cameras leave trailing spaces (Olympus, Nikon) but this library is intended to show
     843        // the actual data within the file.  It is not inconceivable that whitespace may be significant here, so we
     844        // do not trim.  Also, if support is added for writing data back to files, this may cause issues.
     845        // We leave trimming to the presentation layer.
    639846        return o.toString();
    640847    }
    641848
     849    @Nullable
     850    public String getString(int tagType, String charset)
     851    {
     852        byte[] bytes = getByteArray(tagType);
     853        if (bytes==null)
     854            return null;
     855        try {
     856            return new String(bytes, charset);
     857        } catch (UnsupportedEncodingException e) {
     858            return null;
     859        }
     860    }
     861
    642862    /**
    643863     * Returns the object hashed for the particular tag type specified, if available.
     864     *
    644865     * @param tagType the tag type identifier
    645      * @return the tag's value as an Object if available, else null
    646      */
     866     * @return the tag's value as an Object if available, else <code>null</code>
     867     */
     868    @java.lang.SuppressWarnings({ "UnnecessaryBoxing" })
     869    @Nullable
    647870    public Object getObject(int tagType)
    648871    {
    649         return _tagMap.get(new Integer(tagType));
     872        return _tagMap.get(Integer.valueOf(tagType));
    650873    }
    651874
     
    654877    /**
    655878     * Returns the name of a specified tag as a String.
     879     *
    656880     * @param tagType the tag type identifier
    657881     * @return the tag's name as a String
    658882     */
     883    @NotNull
    659884    public String getTagName(int tagType)
    660885    {
    661         Integer key = new Integer(tagType);
    662         HashMap nameMap = getTagNameMap();
    663         if (!nameMap.containsKey(key)) {
     886        HashMap<Integer, String> nameMap = getTagNameMap();
     887        if (!nameMap.containsKey(tagType)) {
    664888            String hex = Integer.toHexString(tagType);
    665             while (hex.length()<4) {
     889            while (hex.length() < 4) {
    666890                hex = "0" + hex;
    667891            }
    668892            return "Unknown tag (0x" + hex + ")";
    669893        }
    670         return (String)nameMap.get(key);
     894        return nameMap.get(tagType);
    671895    }
    672896
     
    674898     * Provides a description of a tag's value using the descriptor set by
    675899     * <code>setDescriptor(Descriptor)</code>.
     900     *
    676901     * @param tagType the tag type identifier
    677902     * @return the tag value's description as a String
    678      * @throws MetadataException if a descriptor hasn't been set, or if an error
    679      * occurs during calculation of the description within the Descriptor
    680      */
    681     public String getDescription(int tagType) throws MetadataException
    682     {
    683         if (_descriptor==null) {
    684             throw new MetadataException("a descriptor must be set using setDescriptor(...) before descriptions can be provided");
    685         }
    686 
     903     */
     904    @Nullable
     905    public String getDescription(int tagType)
     906    {
     907        assert(_descriptor != null);
    687908        return _descriptor.getDescription(tagType);
    688909    }
  • trunk/src/com/drew/metadata/Metadata.java

    r4231 r6127  
    11/*
    2  * Metadata.java
     2 * Copyright 2002-2012 Drew Noakes
    33 *
    4  * This class is public domain software - that is, you can do whatever you want
    5  * with it, and include it software that is licensed under the GNU or the
    6  * BSD license, or whatever other licence you choose, including proprietary
    7  * closed source licenses.  Similarly, I release this Java version under the
    8  * same license, though I do ask that you leave this header in tact.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make modifications to this code that you think would benefit the
    11  * wider community, please send me a copy and I'll post it on my site.
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    129 *
    13  * If you make use of this code, I'd appreciate hearing about it.
    14  *   drew.noakes@drewnoakes.com
    15  * Latest version of this software kept at
    16  *   http://drewnoakes.com/
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
    1715 *
    18  * Created on 28 April 2002, 17:40
    19  * Modified 04 Aug 2002
    20  * - Adjusted javadoc
    21  * - Added
    22  * Modified 29 Oct 2002 (v1.2)
    23  * - Stored IFD directories in separate tag-spaces
    24  * - iterator() now returns an Iterator over a list of TagValue objects
    25  * - More get*Description() methods to detail GPS tags, among others
    26  * - Put spaces between words of tag name for presentation reasons (they had no
    27  *   significance in compound form)
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    2820 */
    2921package com.drew.metadata;
    3022
    31 import java.io.Serializable;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
     25
    3226import java.util.ArrayList;
     27import java.util.Collection;
    3328import java.util.HashMap;
    34 import java.util.Iterator;
     29import java.util.Map;
    3530
    3631/**
    37  * Result from an exif extraction operation, containing all tags, their
    38  * values and support for retrieving them.
    39  * @author  Drew Noakes http://drewnoakes.com
     32 * A top-level object to hold the various types of metadata (Exif/IPTC/etc) related to one entity (such as a file
     33 * or stream).
     34 * <p/>
     35 * Metadata objects may contain zero or more directories.  Each directory may contain zero or more tags with
     36 * corresponding values.
     37 *
     38 * @author Drew Noakes http://drewnoakes.com
    4039 */
    41 public final class Metadata implements Serializable
     40public final class Metadata
    4241{
    43     /**
    44      *
    45      */
    46     private final HashMap directoryMap;
    47 
     42    @NotNull
     43    private final Map<Class<? extends Directory>,Directory> _directoryByClass = new HashMap<Class<? extends Directory>, Directory>();
     44   
    4845    /**
    4946     * List of Directory objects set against this object.  Keeping a list handy makes
    5047     * creation of an Iterator and counting tags simple.
    5148     */
    52     private final ArrayList directoryList;
     49    @NotNull
     50    private final Collection<Directory> _directoryList = new ArrayList<Directory>();
    5351
    5452    /**
    55      * Creates a new instance of Metadata.  Package private.
     53     * Returns an objects for iterating over Directory objects in the order in which they were added.
     54     *
     55     * @return an iterable collection of directories
    5656     */
    57     public Metadata()
     57    @NotNull
     58    public Iterable<Directory> getDirectories()
    5859    {
    59         directoryMap = new HashMap();
    60         directoryList = new ArrayList();
    61     }
    62 
    63 
    64 // OTHER METHODS
    65 
    66     /**
    67      * Creates an Iterator over the tag types set against this image, preserving the order
    68      * in which they were set.  Should the same tag have been set more than once, it's first
    69      * position is maintained, even though the final value is used.
    70      * @return an Iterator of tag types set for this image
    71      */
    72     public Iterator getDirectoryIterator()
    73     {
    74         return directoryList.iterator();
     60        return _directoryList;
    7561    }
    7662
    7763    /**
    7864     * Returns a count of unique directories in this metadata collection.
     65     *
    7966     * @return the number of unique directory types set for this metadata collection
    8067     */
    8168    public int getDirectoryCount()
    8269    {
    83         return directoryList.size();
     70        return _directoryList.size();
    8471    }
    8572
     
    8875     * such a directory, it is returned.  Otherwise a new instance of this directory will be created and stored within
    8976     * this Metadata object.
     77     *
    9078     * @param type the type of the Directory implementation required.
    9179     * @return a directory of the specified type.
    9280     */
    93     public Directory getDirectory(Class type)
     81    @NotNull
     82    @SuppressWarnings("unchecked")
     83    public <T extends Directory> T getOrCreateDirectory(@NotNull Class<T> type)
    9484    {
    95         if (!Directory.class.isAssignableFrom(type)) {
    96             throw new RuntimeException("Class type passed to getDirectory must be an implementation of com.drew.metadata.Directory");
    97         }
     85        // We suppress the warning here as the code asserts a map signature of Class<T>,T.
     86        // So after get(Class<T>) it is for sure the result is from type T.
     87
    9888        // check if we've already issued this type of directory
    99         if (directoryMap.containsKey(type)) {
    100             return (Directory)directoryMap.get(type);
    101         }
    102         Object directory;
     89        if (_directoryByClass.containsKey(type))
     90            return (T)_directoryByClass.get(type);
     91
     92        T directory;
    10393        try {
    10494            directory = type.newInstance();
     
    10696            throw new RuntimeException("Cannot instantiate provided Directory type: " + type.toString());
    10797        }
    108         // store the directory in case it's requested later
    109         directoryMap.put(type, directory);
    110         directoryList.add(directory);
    111         return (Directory)directory;
     98        // store the directory
     99        _directoryByClass.put(type, directory);
     100        _directoryList.add(directory);
     101
     102        return directory;
     103    }
     104
     105    /**
     106     * If this <code>Metadata</code> object contains a <code>Directory</code> of the specified type, it is returned.
     107     * Otherwise <code>null</code> is returned.
     108     *
     109     * @param type the Directory type
     110     * @param <T> the Directory type
     111     * @return a Directory of type T if it exists in this Metadata object, otherwise <code>null</code>.
     112     */
     113    @Nullable
     114    @SuppressWarnings("unchecked")
     115    public <T extends Directory> T getDirectory(@NotNull Class<T> type)
     116    {
     117        // We suppress the warning here as the code asserts a map signature of Class<T>,T.
     118        // So after get(Class<T>) it is for sure the result is from type T.
     119
     120        return (T)_directoryByClass.get(type);
    112121    }
    113122
    114123    /**
    115124     * Indicates whether a given directory type has been created in this metadata
    116      * repository.  Directories are created by calling getDirectory(Class).
     125     * repository.  Directories are created by calling <code>getOrCreateDirectory(Class)</code>.
     126     *
    117127     * @param type the Directory type
    118128     * @return true if the metadata directory has been created
    119129     */
    120     public boolean containsDirectory(Class type)
     130    public boolean containsDirectory(Class<? extends Directory> type)
    121131    {
    122         return directoryMap.containsKey(type);
     132        return _directoryByClass.containsKey(type);
     133    }
     134
     135    /**
     136     * Indicates whether any errors were reported during the reading of metadata values.
     137     * This value will be true if Directory.hasErrors() is true for one of the contained Directory objects.
     138     *
     139     * @return whether one of the contained directories has an error
     140     */
     141    public boolean hasErrors()
     142    {
     143        for (Directory directory : _directoryList) {
     144            if (directory.hasErrors())
     145                return true;
     146        }
     147        return false;
    123148    }
    124149}
  • trunk/src/com/drew/metadata/MetadataException.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 13-Nov-2002 18:10:23 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata;
    1822
    1923import com.drew.lang.CompoundException;
     24import com.drew.lang.annotations.Nullable;
    2025
    2126/**
     27 * Base class for all metadata specific exceptions.
    2228 *
     29 * @author Drew Noakes http://drewnoakes.com
    2330 */
    2431public class MetadataException extends CompoundException
    2532{
    26     public MetadataException(String msg)
     33    private static final long serialVersionUID = 8612756143363919682L;
     34
     35    public MetadataException(@Nullable String msg)
    2736    {
    2837        super(msg);
    2938    }
    3039
    31     public MetadataException(Throwable exception)
     40    public MetadataException(@Nullable Throwable exception)
    3241    {
    3342        super(exception);
    3443    }
    3544
    36     public MetadataException(String msg, Throwable innerException)
     45    public MetadataException(@Nullable String msg, @Nullable Throwable innerException)
    3746    {
    3847        super(msg, innerException);
  • trunk/src/com/drew/metadata/MetadataReader.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 26-Nov-2002 11:21:43 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata;
    1822
     23import com.drew.lang.BufferReader;
     24import com.drew.lang.annotations.NotNull;
     25
    1926/**
     27 * Interface through which all classes responsible for decoding a particular type of metadata may be called.
     28 * Note that the data source is not specified on this interface.  Instead it is suggested that implementations
     29 * take their data within a constructor.  Constructors might be overloaded to allow for different sources, such as
     30 * files, streams and byte arrays.  As such, instances of implementations of this interface would be single-use and
     31 * not thread-safe.
    2032 *
     33 * @author Drew Noakes http://drewnoakes.com
    2134 */
    2235public interface MetadataReader
    2336{
    24     public Metadata extract();
    25 
    26     public Metadata extract(Metadata metadata);
     37    /**
     38     * Extract metadata from the source and merge it into an existing Metadata object.
     39     *
     40     * @param reader   The reader from which the metadata should be extracted.
     41     * @param metadata The Metadata object into which extracted values should be merged.
     42     */
     43    public void extract(@NotNull final BufferReader reader, @NotNull final Metadata metadata);
    2744}
  • trunk/src/com/drew/metadata/Tag.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 26-Nov-2002 18:29:12 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata;
    1822
    19 import java.io.Serializable;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
    2025
    2126/**
     27 * Models a particular tag within a directory and provides methods for obtaining its value.  Note that a Tag instance is
     28 * specific to a particular metadata extraction and cannot be reused.
    2229 *
     30 * @author Drew Noakes http://drewnoakes.com
    2331 */
    24 public class Tag implements Serializable
     32public class Tag
    2533{
    2634    private final int _tagType;
     35    @NotNull
    2736    private final Directory _directory;
    2837
    29     public Tag(int tagType, Directory directory)
     38    public Tag(int tagType, @NotNull Directory directory)
    3039    {
    3140        _tagType = tagType;
     
    3544    /**
    3645     * Gets the tag type as an int
     46     *
    3747     * @return the tag type as an int
    3848     */
     
    4555     * Gets the tag type in hex notation as a String with padded leading
    4656     * zeroes if necessary (i.e. <code>0x100E</code>).
     57     *
    4758     * @return the tag type as a string in hexadecimal notation
    4859     */
     60    @NotNull
    4961    public String getTagTypeHex()
    5062    {
     
    5769     * Get a description of the tag's value, considering enumerated values
    5870     * and units.
     71     *
    5972     * @return a description of the tag's value
    6073     */
    61     public String getDescription() throws MetadataException
     74    @Nullable
     75    public String getDescription()
    6276    {
    6377        return _directory.getDescription(_tagType);
     
    6781     * Get the name of the tag, such as <code>Aperture</code>, or
    6882     * <code>InteropVersion</code>.
     83     *
    6984     * @return the tag's name
    7085     */
     86    @NotNull
    7187    public String getTagName()
    7288    {
     
    7793     * Get the name of the directory in which the tag exists, such as
    7894     * <code>Exif</code>, <code>GPS</code> or <code>Interoperability</code>.
     95     *
    7996     * @return name of the directory in which this tag exists
    8097     */
     98    @NotNull
    8199    public String getDirectoryName()
    82100    {
     
    85103
    86104    /**
    87      * A basic representation of the tag's type and value in format:
    88      * <code>FNumber - F2.8</code>.
     105     * A basic representation of the tag's type and value.  EG: <code>[FNumber] F2.8</code>.
     106     *
    89107     * @return the tag's type and value
    90108     */
     109    @NotNull
    91110    public String toString()
    92111    {
    93         String description;
    94         try {
    95             description = getDescription();
    96         } catch (MetadataException e) {
     112        String description = getDescription();
     113        if (description==null)
    97114            description = _directory.getString(getTagType()) + " (unable to formulate description)";
    98         }
    99115        return "[" + _directory.getName() + "] " + getTagName() + " - " + description;
    100116    }
  • trunk/src/com/drew/metadata/TagDescriptor.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
     9 *
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1420 */
    1521package com.drew.metadata;
    1622
    17 import java.io.Serializable;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
     25
     26import java.lang.reflect.Array;
    1827
    1928/**
    2029 * Abstract base class for all tag descriptor classes.  Implementations are responsible for
    21  * providing the human-readable string represenation of tag values stored in a directory.
     30 * providing the human-readable string representation of tag values stored in a directory.
    2231 * The directory is provided to the tag descriptor via its constructor.
     32 *
     33 * @author Drew Noakes http://drewnoakes.com
    2334 */
    24 public abstract class TagDescriptor implements Serializable
     35public abstract class TagDescriptor<T extends Directory>
    2536{
    26     protected final Directory _directory;
     37    @NotNull
     38    protected final T _directory;
    2739
    28     public TagDescriptor(Directory directory)
     40    public TagDescriptor(@NotNull T directory)
    2941    {
    3042        _directory = directory;
     
    3446     * Returns a descriptive value of the the specified tag for this image.
    3547     * Where possible, known values will be substituted here in place of the raw
    36      * tokens actually kept in the Exif segment.  If no substitution is
    37      * available, the value provided by getString(int) will be returned.
    38      * <p>
    39      * This and getString(int) are the only 'get' methods that won't throw an
    40      * exception.
     48     * tokens actually kept in the metadata segment.  If no substitution is
     49     * available, the value provided by <code>getString(tagType)</code> will be returned.
     50     *
    4151     * @param tagType the tag to find a description for
    4252     * @return a description of the image's value for the specified tag, or
    4353     *         <code>null</code> if the tag hasn't been defined.
    4454     */
    45     public abstract String getDescription(int tagType) throws MetadataException;
     55    @Nullable
     56    public String getDescription(int tagType)
     57    {
     58        Object object = _directory.getObject(tagType);
     59
     60        if (object==null)
     61            return null;
     62
     63        // special presentation for long arrays
     64        if (object.getClass().isArray()) {
     65            final int length = Array.getLength(object);
     66            if (length > 16) {
     67                final String componentTypeName = object.getClass().getComponentType().getName();
     68                return String.format("[%d %s%s]", length, componentTypeName, length==1 ? "" : "s");
     69            }
     70        }
     71
     72        // no special handling required, so use default conversion to a string
     73        return _directory.getString(tagType);
     74    }
     75
     76    /**
     77     * Takes a series of 4 bytes from the specified offset, and converts these to a
     78     * well-known version number, where possible.
     79     * <p/>
     80     * Two different formats are processed:
     81     * <ul>
     82     *     <li>[30 32 31 30] -&gt; 2.10</li>
     83     *     <li>[0 1 0 0] -&gt; 1.00</li>
     84     * </ul>
     85     * @param components the four version values
     86     * @param majorDigits the number of components to be
     87     * @return the version as a string of form "2.10" or null if the argument cannot be converted
     88     */
     89    @Nullable
     90    public static String convertBytesToVersionString(@Nullable int[] components, final int majorDigits)
     91    {
     92        if (components==null)
     93            return null;
     94        StringBuilder version = new StringBuilder();
     95        for (int i = 0; i < 4 && i < components.length; i++) {
     96            if (i == majorDigits)
     97                version.append('.');
     98            char c = (char)components[i];
     99            if (c < '0')
     100                c += '0';
     101            if (i == 0 && c=='0')
     102                continue;
     103            version.append(c);
     104        }
     105        return version.toString();
     106    }
    46107}
  • trunk/src/com/drew/metadata/exif/CanonMakernoteDescriptor.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
    19 import com.drew.metadata.Directory;
    20 import com.drew.metadata.MetadataException;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
    2125import com.drew.metadata.TagDescriptor;
    2226
    2327/**
     28 * Provides human-readable string representations of tag values stored in a <code>CanonMakernoteDirectory</code>.
    2429 *
     30 * @author Drew Noakes http://drewnoakes.com
    2531 */
    26 public class CanonMakernoteDescriptor extends TagDescriptor
     32public class CanonMakernoteDescriptor extends TagDescriptor<CanonMakernoteDirectory>
    2733{
    28     public CanonMakernoteDescriptor(Directory directory)
     34    public CanonMakernoteDescriptor(@NotNull CanonMakernoteDirectory directory)
    2935    {
    3036        super(directory);
    3137    }
    3238
    33     public String getDescription(int tagType) throws MetadataException
     39    @Nullable
     40    public String getDescription(int tagType)
    3441    {
    3542        switch (tagType) {
    36             case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY:
     43            case CanonMakernoteDirectory.TAG_CANON_SERIAL_NUMBER:
     44                return getSerialNumberDescription();
     45            case CanonMakernoteDirectory.CameraSettings.TAG_FLASH_ACTIVITY:
    3746                return getFlashActivityDescription();
    38             case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE:
     47            case CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_TYPE:
    3948                return getFocusTypeDescription();
    40             case CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM:
     49            case CanonMakernoteDirectory.CameraSettings.TAG_DIGITAL_ZOOM:
    4150                return getDigitalZoomDescription();
    42             case CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY:
     51            case CanonMakernoteDirectory.CameraSettings.TAG_QUALITY:
    4352                return getQualityDescription();
    44             case CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE:
     53            case CanonMakernoteDirectory.CameraSettings.TAG_MACRO_MODE:
    4554                return getMacroModeDescription();
    46             case CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY:
     55            case CanonMakernoteDirectory.CameraSettings.TAG_SELF_TIMER_DELAY:
    4756                return getSelfTimerDelayDescription();
    48             case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE:
     57            case CanonMakernoteDirectory.CameraSettings.TAG_FLASH_MODE:
    4958                return getFlashModeDescription();
    50             case CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE:
     59            case CanonMakernoteDirectory.CameraSettings.TAG_CONTINUOUS_DRIVE_MODE:
    5160                return getContinuousDriveModeDescription();
    52             case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1:
     61            case CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_1:
    5362                return getFocusMode1Description();
    54             case CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE:
     63            case CanonMakernoteDirectory.CameraSettings.TAG_IMAGE_SIZE:
    5564                return getImageSizeDescription();
    56             case CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE:
     65            case CanonMakernoteDirectory.CameraSettings.TAG_EASY_SHOOTING_MODE:
    5766                return getEasyShootingModeDescription();
    58             case CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST:
     67            case CanonMakernoteDirectory.CameraSettings.TAG_CONTRAST:
    5968                return getContrastDescription();
    60             case CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION:
     69            case CanonMakernoteDirectory.CameraSettings.TAG_SATURATION:
    6170                return getSaturationDescription();
    62             case CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS:
     71            case CanonMakernoteDirectory.CameraSettings.TAG_SHARPNESS:
    6372                return getSharpnessDescription();
    64             case CanonMakernoteDirectory.TAG_CANON_STATE1_ISO:
     73            case CanonMakernoteDirectory.CameraSettings.TAG_ISO:
    6574                return getIsoDescription();
    66             case CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE:
     75            case CanonMakernoteDirectory.CameraSettings.TAG_METERING_MODE:
    6776                return getMeteringModeDescription();
    68             case CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED:
     77            case CanonMakernoteDirectory.CameraSettings.TAG_AF_POINT_SELECTED:
    6978                return getAfPointSelectedDescription();
    70             case CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE:
     79            case CanonMakernoteDirectory.CameraSettings.TAG_EXPOSURE_MODE:
    7180                return getExposureModeDescription();
    72             case CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH:
     81            case CanonMakernoteDirectory.CameraSettings.TAG_LONG_FOCAL_LENGTH:
    7382                return getLongFocalLengthDescription();
    74             case CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH:
     83            case CanonMakernoteDirectory.CameraSettings.TAG_SHORT_FOCAL_LENGTH:
    7584                return getShortFocalLengthDescription();
    76             case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM:
     85            case CanonMakernoteDirectory.CameraSettings.TAG_FOCAL_UNITS_PER_MM:
    7786                return getFocalUnitsPerMillimetreDescription();
    78             case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS:
     87            case CanonMakernoteDirectory.CameraSettings.TAG_FLASH_DETAILS:
    7988                return getFlashDetailsDescription();
    80             case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2:
     89            case CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_2:
    8190                return getFocusMode2Description();
    82             case CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE:
     91            case CanonMakernoteDirectory.FocalLength.TAG_WHITE_BALANCE:
    8392                return getWhiteBalanceDescription();
    84             case CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED:
     93            case CanonMakernoteDirectory.FocalLength.TAG_AF_POINT_USED:
    8594                return getAfPointUsedDescription();
    86             case CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS:
     95            case CanonMakernoteDirectory.FocalLength.TAG_FLASH_BIAS:
    8796                return getFlashBiasDescription();
    88             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION:
    89                 return getLongExposureNoiseReductionDescription();
    90             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS:
    91                 return getShutterAutoExposureLockButtonDescription();
    92             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP:
    93                 return getMirrorLockupDescription();
    94             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL:
    95                 return getTvAndAvExposureLevelDescription();
    96             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT:
    97                 return getAutoFocusAssistLightDescription();
    98             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE:
    99                 return getShutterSpeedInAvModeDescription();
    100             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING:
    101                 return getAutoExposureBrackettingSequenceAndAutoCancellationDescription();
    102             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC:
    103                 return getShutterCurtainSyncDescription();
    104             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP:
    105                 return getLensAutoFocusStopButtonDescription();
    106             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION:
    107                 return getFillFlashReductionDescription();
    108             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN:
    109                 return getMenuButtonReturnPositionDescription();
    110             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION:
    111                 return getSetButtonFunctionWhenShootingDescription();
    112             case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING:
    113                 return getSensorCleaningDescription();
    114             default:
    115                 return _directory.getString(tagType);
    116         }
    117     }
    118 
    119     public String getLongExposureNoiseReductionDescription() throws MetadataException
    120     {
    121         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION)) return null;
    122         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION);
     97
     98            // It turns out that these values are dependent upon the camera model and therefore the below code was
     99            // incorrect for some Canon models.  This needs to be revisited.
     100
     101//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION:
     102//                return getLongExposureNoiseReductionDescription();
     103//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS:
     104//                return getShutterAutoExposureLockButtonDescription();
     105//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP:
     106//                return getMirrorLockupDescription();
     107//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL:
     108//                return getTvAndAvExposureLevelDescription();
     109//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT:
     110//                return getAutoFocusAssistLightDescription();
     111//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE:
     112//                return getShutterSpeedInAvModeDescription();
     113//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING:
     114//                return getAutoExposureBrackettingSequenceAndAutoCancellationDescription();
     115//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC:
     116//                return getShutterCurtainSyncDescription();
     117//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP:
     118//                return getLensAutoFocusStopButtonDescription();
     119//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION:
     120//                return getFillFlashReductionDescription();
     121//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN:
     122//                return getMenuButtonReturnPositionDescription();
     123//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION:
     124//                return getSetButtonFunctionWhenShootingDescription();
     125//            case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING:
     126//                return getSensorCleaningDescription();
     127            default:
     128                return super.getDescription(tagType);
     129        }
     130    }
     131
     132    @Nullable
     133    public String getSerialNumberDescription()
     134    {
     135        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_SERIAL_NUMBER);
     136        if (value==null)
     137            return null;
     138        return String.format("%04X%05d", (value >> 8) & 0xFF, value & 0xFF);
     139    }
     140
     141/*
     142    @Nullable
     143    public String getLongExposureNoiseReductionDescription()
     144    {
     145        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION);
     146        if (value==null)
     147            return null;
    123148        switch (value) {
    124149            case 0:     return "Off";
     
    127152        }
    128153    }
    129     public String getShutterAutoExposureLockButtonDescription() throws MetadataException
    130     {
    131         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS)) return null;
    132         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS);
     154
     155    @Nullable
     156    public String getShutterAutoExposureLockButtonDescription()
     157    {
     158        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS);
     159        if (value==null)
     160            return null;
    133161        switch (value) {
    134162            case 0:     return "AF/AE lock";
     
    139167        }
    140168    }
    141     public String getMirrorLockupDescription() throws MetadataException
    142     {
    143         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP)) return null;
    144         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP);
     169
     170    @Nullable
     171    public String getMirrorLockupDescription()
     172    {
     173        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP);
     174        if (value==null)
     175            return null;
    145176        switch (value) {
    146177            case 0:     return "Disabled";
     
    149180        }
    150181    }
    151     public String getTvAndAvExposureLevelDescription() throws MetadataException
    152     {
    153         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL)) return null;
    154         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL);
     182
     183    @Nullable
     184    public String getTvAndAvExposureLevelDescription()
     185    {
     186        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL);
     187        if (value==null)
     188            return null;
    155189        switch (value) {
    156190            case 0:     return "1/2 stop";
     
    159193        }
    160194    }
    161     public String getAutoFocusAssistLightDescription() throws MetadataException
    162     {
    163         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT)) return null;
    164         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT);
     195
     196    @Nullable
     197    public String getAutoFocusAssistLightDescription()
     198    {
     199        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT);
     200        if (value==null)
     201            return null;
    165202        switch (value) {
    166203            case 0:     return "On (Auto)";
     
    169206        }
    170207    }
    171     public String getShutterSpeedInAvModeDescription() throws MetadataException
    172     {
    173         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE)) return null;
    174         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE);
     208
     209    @Nullable
     210    public String getShutterSpeedInAvModeDescription()
     211    {
     212        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE);
     213        if (value==null)
     214            return null;
    175215        switch (value) {
    176216            case 0:     return "Automatic";
     
    179219        }
    180220    }
    181     public String getAutoExposureBrackettingSequenceAndAutoCancellationDescription() throws MetadataException
    182     {
    183         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING)) return null;
    184         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING);
     221
     222    @Nullable
     223    public String getAutoExposureBrackettingSequenceAndAutoCancellationDescription()
     224    {
     225        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING);
     226        if (value==null)
     227            return null;
    185228        switch (value) {
    186229            case 0:     return "0,-,+ / Enabled";
     
    191234        }
    192235    }
    193     public String getShutterCurtainSyncDescription() throws MetadataException
    194     {
    195         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC)) return null;
    196         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC);
     236
     237    @Nullable
     238    public String getShutterCurtainSyncDescription()
     239    {
     240        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC);
     241        if (value==null)
     242            return null;
    197243        switch (value) {
    198244            case 0:     return "1st Curtain Sync";
     
    201247        }
    202248    }
    203     public String getLensAutoFocusStopButtonDescription() throws MetadataException
    204     {
    205         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP)) return null;
    206         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP);
     249
     250    @Nullable
     251    public String getLensAutoFocusStopButtonDescription()
     252    {
     253        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP);
     254        if (value==null)
     255            return null;
    207256        switch (value) {
    208257            case 0:     return "AF stop";
     
    212261        }
    213262    }
    214     public String getFillFlashReductionDescription() throws MetadataException
    215     {
    216         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION)) return null;
    217         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION);
     263
     264    @Nullable
     265    public String getFillFlashReductionDescription()
     266    {
     267        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION);
     268        if (value==null)
     269            return null;
    218270        switch (value) {
    219271            case 0:     return "Enabled";
     
    222274        }
    223275    }
    224     public String getMenuButtonReturnPositionDescription() throws MetadataException
    225     {
    226         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN)) return null;
    227         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN);
     276
     277    @Nullable
     278    public String getMenuButtonReturnPositionDescription()
     279    {
     280        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN);
     281        if (value==null)
     282            return null;
    228283        switch (value) {
    229284            case 0:     return "Top";
     
    233288        }
    234289    }
    235     public String getSetButtonFunctionWhenShootingDescription() throws MetadataException
    236     {
    237         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION)) return null;
    238         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION);
     290
     291    @Nullable
     292    public String getSetButtonFunctionWhenShootingDescription()
     293    {
     294        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION);
     295        if (value==null)
     296            return null;
    239297        switch (value) {
    240298            case 0:     return "Not Assigned";
     
    245303        }
    246304    }
    247     public String getSensorCleaningDescription() throws MetadataException
    248     {
    249         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING)) return null;
    250         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING);
     305
     306    @Nullable
     307    public String getSensorCleaningDescription()
     308    {
     309        Integer value = _directory.getInteger(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING);
     310        if (value==null)
     311            return null;
    251312        switch (value) {
    252313            case 0:     return "Disabled";
     
    255316        }
    256317    }
    257 
    258     public String getFlashBiasDescription() throws MetadataException
    259     {
    260         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)) return null;
    261 
    262         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS);
     318*/
     319
     320    @Nullable
     321    public String getFlashBiasDescription()
     322    {
     323        Integer value = _directory.getInteger(CanonMakernoteDirectory.FocalLength.TAG_FLASH_BIAS);
     324
     325        if (value==null)
     326            return null;
    263327
    264328        boolean isNegative = false;
     
    278342    }
    279343
    280     public String getAfPointUsedDescription() throws MetadataException
    281     {
    282         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED)) return null;
    283         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED);
     344    @Nullable
     345    public String getAfPointUsedDescription()
     346    {
     347        Integer value = _directory.getInteger(CanonMakernoteDirectory.FocalLength.TAG_AF_POINT_USED);
     348        if (value==null)
     349            return null;
    284350        if ((value & 0x7) == 0) {
    285351            return "Right";
     
    293359    }
    294360
    295     public String getWhiteBalanceDescription() throws MetadataException
    296     {
    297         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE)) return null;
    298         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE);
     361    @Nullable
     362    public String getWhiteBalanceDescription()
     363    {
     364        Integer value = _directory.getInteger(CanonMakernoteDirectory.FocalLength.TAG_WHITE_BALANCE);
     365        if (value==null)
     366            return null;
    299367        switch (value) {
    300368            case 0:
     
    307375                return "Tungsten";
    308376            case 4:
    309                 return "Flourescent";
     377                return "Florescent";
    310378            case 5:
    311379                return "Flash";
     
    317385    }
    318386
    319     public String getFocusMode2Description() throws MetadataException
    320     {
    321         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2)) return null;
    322         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2);
     387    @Nullable
     388    public String getFocusMode2Description()
     389    {
     390        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_2);
     391        if (value==null)
     392            return null;
    323393        switch (value) {
    324394            case 0:
     
    331401    }
    332402
    333     public String getFlashDetailsDescription() throws MetadataException
    334     {
    335         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS)) return null;
    336         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS);
    337         if (((value << 14) & 1) > 0) {
     403    @Nullable
     404    public String getFlashDetailsDescription()
     405    {
     406        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FLASH_DETAILS);
     407        if (value==null)
     408            return null;
     409        if (((value >> 14) & 1) > 0) {
    338410            return "External E-TTL";
    339411        }
    340         if (((value << 13) & 1) > 0) {
     412        if (((value >> 13) & 1) > 0) {
    341413            return "Internal flash";
    342414        }
    343         if (((value << 11) & 1) > 0) {
     415        if (((value >> 11) & 1) > 0) {
    344416            return "FP sync used";
    345417        }
    346         if (((value << 4) & 1) > 0) {
     418        if (((value >> 4) & 1) > 0) {
    347419            return "FP sync enabled";
    348420        }
     
    350422    }
    351423
    352     public String getFocalUnitsPerMillimetreDescription() throws MetadataException
    353     {
    354         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM)) return "";
    355         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM);
     424    @Nullable
     425    public String getFocalUnitsPerMillimetreDescription()
     426    {
     427        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCAL_UNITS_PER_MM);
     428        if (value==null)
     429            return null;
    356430        if (value != 0) {
    357431            return Integer.toString(value);
     
    361435    }
    362436
    363     public String getShortFocalLengthDescription() throws MetadataException
    364     {
    365         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH)) return null;
    366         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH);
     437    @Nullable
     438    public String getShortFocalLengthDescription()
     439    {
     440        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SHORT_FOCAL_LENGTH);
     441        if (value==null)
     442            return null;
    367443        String units = getFocalUnitsPerMillimetreDescription();
    368444        return Integer.toString(value) + " " + units;
    369445    }
    370446
    371     public String getLongFocalLengthDescription() throws MetadataException
    372     {
    373         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH)) return null;
    374         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH);
     447    @Nullable
     448    public String getLongFocalLengthDescription()
     449    {
     450        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_LONG_FOCAL_LENGTH);
     451        if (value==null)
     452            return null;
    375453        String units = getFocalUnitsPerMillimetreDescription();
    376454        return Integer.toString(value) + " " + units;
    377455    }
    378456
    379     public String getExposureModeDescription() throws MetadataException
    380     {
    381         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE)) return null;
    382         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE);
     457    @Nullable
     458    public String getExposureModeDescription()
     459    {
     460        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_EXPOSURE_MODE);
     461        if (value==null)
     462            return null;
    383463        switch (value) {
    384464            case 0:
     
    399479    }
    400480
    401     public String getAfPointSelectedDescription() throws MetadataException
    402     {
    403         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED)) return null;
    404         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED);
     481    @Nullable
     482    public String getAfPointSelectedDescription()
     483    {
     484        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_AF_POINT_SELECTED);
     485        if (value==null)
     486            return null;
    405487        switch (value) {
    406488            case 0x3000:
     
    419501    }
    420502
    421     public String getMeteringModeDescription() throws MetadataException
    422     {
    423         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE)) return null;
    424         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE);
     503    @Nullable
     504    public String getMeteringModeDescription()
     505    {
     506        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_METERING_MODE);
     507        if (value==null)
     508            return null;
    425509        switch (value) {
    426510            case 3:
     
    435519    }
    436520
    437     public String getIsoDescription() throws MetadataException
    438     {
    439         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO)) return null;
    440         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO);
     521    @Nullable
     522    public String getIsoDescription()
     523    {
     524        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_ISO);
     525        if (value==null)
     526            return null;
     527
     528        // Canon PowerShot S3 is special
     529        int canonMask = 0x4000;
     530        if ((value & canonMask) > 0)
     531            return "" + (value & ~canonMask);
     532
    441533        switch (value) {
    442534            case 0:
     
    457549    }
    458550
    459     public String getSharpnessDescription() throws MetadataException
    460     {
    461         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS)) return null;
    462         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS);
     551    @Nullable
     552    public String getSharpnessDescription()
     553    {
     554        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SHARPNESS);
     555        if (value==null)
     556            return null;
    463557        switch (value) {
    464558            case 0xFFFF:
     
    473567    }
    474568
    475     public String getSaturationDescription() throws MetadataException
    476     {
    477         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION)) return null;
    478         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION);
     569    @Nullable
     570    public String getSaturationDescription()
     571    {
     572        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SATURATION);
     573        if (value==null)
     574            return null;
    479575        switch (value) {
    480576            case 0xFFFF:
     
    489585    }
    490586
    491     public String getContrastDescription() throws MetadataException
    492     {
    493         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST)) return null;
    494         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST);
     587    @Nullable
     588    public String getContrastDescription()
     589    {
     590        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_CONTRAST);
     591        if (value==null)
     592            return null;
    495593        switch (value) {
    496594            case 0xFFFF:
     
    505603    }
    506604
    507     public String getEasyShootingModeDescription() throws MetadataException
    508     {
    509         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE)) return null;
    510         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE);
     605    @Nullable
     606    public String getEasyShootingModeDescription()
     607    {
     608        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_EASY_SHOOTING_MODE);
     609        if (value==null)
     610            return null;
    511611        switch (value) {
    512612            case 0:
     
    539639    }
    540640
    541     public String getImageSizeDescription() throws MetadataException
    542     {
    543         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE)) return null;
    544         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE);
     641    @Nullable
     642    public String getImageSizeDescription()
     643    {
     644        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_IMAGE_SIZE);
     645        if (value==null)
     646            return null;
    545647        switch (value) {
    546648            case 0:
     
    555657    }
    556658
    557     public String getFocusMode1Description() throws MetadataException
    558     {
    559         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1)) return null;
    560         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1);
     659    @Nullable
     660    public String getFocusMode1Description()
     661    {
     662        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_MODE_1);
     663        if (value==null)
     664            return null;
    561665        switch (value) {
    562666            case 0:
     
    580684    }
    581685
    582     public String getContinuousDriveModeDescription() throws MetadataException
    583     {
    584         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE)) return null;
    585         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE);
    586         switch (value) {
    587             case 0:
    588                 if (_directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY) == 0) {
    589                     return "Single shot";
    590                 } else {
    591                     return "Single shot with self-timer";
    592                 }
     686    @Nullable
     687    public String getContinuousDriveModeDescription()
     688    {
     689        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_CONTINUOUS_DRIVE_MODE);
     690        if (value==null)
     691            return null;
     692        switch (value) {
     693            case 0:
     694                final Integer delay = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SELF_TIMER_DELAY);
     695                if (delay!=null)
     696                    return delay == 0 ? "Single shot" : "Single shot with self-timer";
    593697            case 1:
    594698                return "Continuous";
    595             default:
    596                 return "Unknown (" + value + ")";
    597         }
    598     }
    599 
    600     public String getFlashModeDescription() throws MetadataException
    601     {
    602         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE)) return null;
    603         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE);
     699        }
     700        return "Unknown (" + value + ")";
     701    }
     702
     703    @Nullable
     704    public String getFlashModeDescription()
     705    {
     706        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FLASH_MODE);
     707        if (value==null)
     708            return null;
    604709        switch (value) {
    605710            case 0:
     
    619724            case 16:
    620725                // note: this value not set on Canon D30
    621                 return "Extenal flash";
    622             default:
    623                 return "Unknown (" + value + ")";
    624         }
    625     }
    626 
    627     public String getSelfTimerDelayDescription() throws MetadataException
    628     {
    629         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY)) return null;
    630         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY);
     726                return "External flash";
     727            default:
     728                return "Unknown (" + value + ")";
     729        }
     730    }
     731
     732    @Nullable
     733    public String getSelfTimerDelayDescription()
     734    {
     735        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_SELF_TIMER_DELAY);
     736        if (value==null)
     737            return null;
    631738        if (value == 0) {
    632739            return "Self timer not used";
     
    637744    }
    638745
    639     public String getMacroModeDescription() throws MetadataException
    640     {
    641         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE)) return null;
    642         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE);
     746    @Nullable
     747    public String getMacroModeDescription()
     748    {
     749        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_MACRO_MODE);
     750        if (value==null)
     751            return null;
    643752        switch (value) {
    644753            case 1:
     
    651760    }
    652761
    653     public String getQualityDescription() throws MetadataException
    654     {
    655         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY)) return null;
    656         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY);
     762    @Nullable
     763    public String getQualityDescription()
     764    {
     765        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_QUALITY);
     766        if (value==null)
     767            return null;
    657768        switch (value) {
    658769            case 2:
     
    667778    }
    668779
    669     public String getDigitalZoomDescription() throws MetadataException
    670     {
    671         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM)) return null;
    672         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM);
     780    @Nullable
     781    public String getDigitalZoomDescription()
     782    {
     783        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_DIGITAL_ZOOM);
     784        if (value==null)
     785            return null;
    673786        switch (value) {
    674787            case 0:
     
    683796    }
    684797
    685     public String getFocusTypeDescription() throws MetadataException
    686     {
    687         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE)) return null;
    688         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE);
     798    @Nullable
     799    public String getFocusTypeDescription()
     800    {
     801        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FOCUS_TYPE);
     802        if (value==null)
     803            return null;
    689804        switch (value) {
    690805            case 0:
     
    701816    }
    702817
    703     public String getFlashActivityDescription() throws MetadataException
    704     {
    705         if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY)) return null;
    706         int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY);
     818    @Nullable
     819    public String getFlashActivityDescription()
     820    {
     821        Integer value = _directory.getInteger(CanonMakernoteDirectory.CameraSettings.TAG_FLASH_ACTIVITY);
     822        if (value==null)
     823            return null;
    707824        switch (value) {
    708825            case 0:
  • trunk/src/com/drew/metadata/exif/CanonMakernoteDirectory.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
     23import com.drew.lang.annotations.NotNull;
    1924import com.drew.metadata.Directory;
    2025
     
    2732 *
    2833 * Many tag definitions explained here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/canon_mn.html
     34 *
     35 * @author Drew Noakes http://drewnoakes.com
    2936 */
    3037public class CanonMakernoteDirectory extends Directory
    3138{
    32     // CANON cameras have some funny bespoke fields that need further processing...
    33     public static final int TAG_CANON_CAMERA_STATE_1 = 0x0001;
    34     public static final int TAG_CANON_CAMERA_STATE_2 = 0x0004;
    35 
    36     public static final int TAG_CANON_IMAGE_TYPE = 0x0006;
    37     public static final int TAG_CANON_FIRMWARE_VERSION = 0x0007;
    38     public static final int TAG_CANON_IMAGE_NUMBER = 0x0008;
    39     public static final int TAG_CANON_OWNER_NAME = 0x0009;
    40     /**
    41      * To display serial number as on camera use: printf( "%04X%05d", highbyte, lowbyte )
    42      * TODO handle this in CanonMakernoteDescriptor
    43      */
    44     public static final int TAG_CANON_SERIAL_NUMBER = 0x000C;
    45     public static final int TAG_CANON_UNKNOWN_1 = 0x000D;
    46     public static final int TAG_CANON_CUSTOM_FUNCTIONS = 0x000F;
    47 
    48     // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
    49     /**
    50      * 1 = Macro
    51      * 2 = Normal
    52      */
    53     public static final int TAG_CANON_STATE1_MACRO_MODE = 0xC101;
    54     public static final int TAG_CANON_STATE1_SELF_TIMER_DELAY = 0xC102;
    55     /**
    56      * 2 = Normal
    57      * 3 = Fine
    58      * 5 = Superfine
    59      */
    60     public static final int TAG_CANON_STATE1_QUALITY = 0xC103;
    61     /**
    62      * 0 = Flash Not Fired
    63      * 1 = Auto
    64      * 2 = On
    65      * 3 = Red Eye Reduction
    66      * 4 = Slow Synchro
    67      * 5 = Auto + Red Eye Reduction
    68      * 6 = On + Red Eye Reduction
    69      * 16 = External Flash
    70      */
    71     public static final int TAG_CANON_STATE1_FLASH_MODE = 0xC104;
    72     /**
    73      * 0 = Single Frame or Timer Mode
    74      * 1 = Continuous
    75      */
    76     public static final int TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE = 0xC105;
    77     public static final int TAG_CANON_STATE1_UNKNOWN_2 = 0xC106;
    78     /**
    79      * 0 = One-Shot
    80      * 1 = AI Servo
    81      * 2 = AI Focus
    82      * 3 = Manual Focus
    83      * 4 = Single
    84      * 5 = Continuous
    85      * 6 = Manual Focus
    86      */
    87     public static final int TAG_CANON_STATE1_FOCUS_MODE_1 = 0xC107;
    88     public static final int TAG_CANON_STATE1_UNKNOWN_3 = 0xC108;
    89     public static final int TAG_CANON_STATE1_UNKNOWN_4 = 0xC109;
    90     /**
    91      * 0 = Large
    92      * 1 = Medium
    93      * 2 = Small
    94      */
    95     public static final int TAG_CANON_STATE1_IMAGE_SIZE = 0xC10A;
    96     /**
    97      * 0 = Full Auto
    98      * 1 = Manual
    99      * 2 = Landscape
    100      * 3 = Fast Shutter
    101      * 4 = Slow Shutter
    102      * 5 = Night
    103      * 6 = Black & White
    104      * 7 = Sepia
    105      * 8 = Portrait
    106      * 9 = Sports
    107      * 10 = Macro / Close-Up
    108      * 11 = Pan Focus
    109      */
    110     public static final int TAG_CANON_STATE1_EASY_SHOOTING_MODE = 0xC10B;
    111     /**
    112      * 0 = No Digital Zoom
    113      * 1 = 2x
    114      * 2 = 4x
    115      */
    116     public static final int TAG_CANON_STATE1_DIGITAL_ZOOM = 0xC10C;
    117     /**
    118      * 0 = Normal
    119      * 1 = High
    120      * 65535 = Low
    121      */
    122     public static final int TAG_CANON_STATE1_CONTRAST = 0xC10D;
    123     /**
    124      * 0 = Normal
    125      * 1 = High
    126      * 65535 = Low
    127      */
    128     public static final int TAG_CANON_STATE1_SATURATION = 0xC10E;
    129     /**
    130      * 0 = Normal
    131      * 1 = High
    132      * 65535 = Low
    133      */
    134     public static final int TAG_CANON_STATE1_SHARPNESS = 0xC10F;
    135     /**
    136      * 0 = Check ISOSpeedRatings EXIF tag for ISO Speed
    137      * 15 = Auto ISO
    138      * 16 = ISO 50
    139      * 17 = ISO 100
    140      * 18 = ISO 200
    141      * 19 = ISO 400
    142      */
    143     public static final int TAG_CANON_STATE1_ISO = 0xC110;
    144     /**
    145      * 3 = Evaluative
    146      * 4 = Partial
    147      * 5 = Centre Weighted
    148      */
    149     public static final int TAG_CANON_STATE1_METERING_MODE = 0xC111;
    150     /**
    151      * 0 = Manual
    152      * 1 = Auto
    153      * 3 = Close-up (Macro)
    154      * 8 = Locked (Pan Mode)
    155      */
    156     public static final int TAG_CANON_STATE1_FOCUS_TYPE = 0xC112;
    157     /**
    158      * 12288 = None (Manual Focus)
    159      * 12289 = Auto Selected
    160      * 12290 = Right
    161      * 12291 = Centre
    162      * 12292 = Left
    163      */
    164     public static final int TAG_CANON_STATE1_AF_POINT_SELECTED = 0xC113;
    165     /**
    166      * 0 = Easy Shooting (See Easy Shooting Mode)
    167      * 1 = Program
    168      * 2 = Tv-Priority
    169      * 3 = Av-Priority
    170      * 4 = Manual
    171      * 5 = A-DEP
    172      */
    173     public static final int TAG_CANON_STATE1_EXPOSURE_MODE = 0xC114;
    174     public static final int TAG_CANON_STATE1_UNKNOWN_7 = 0xC115;
    175     public static final int TAG_CANON_STATE1_UNKNOWN_8 = 0xC116;
    176     public static final int TAG_CANON_STATE1_LONG_FOCAL_LENGTH = 0xC117;
    177     public static final int TAG_CANON_STATE1_SHORT_FOCAL_LENGTH = 0xC118;
    178     public static final int TAG_CANON_STATE1_FOCAL_UNITS_PER_MM = 0xC119;
    179     public static final int TAG_CANON_STATE1_UNKNOWN_9 = 0xC11A;
    180     public static final int TAG_CANON_STATE1_UNKNOWN_10 = 0xC11B;
    181     /**
    182      * 0 = Flash Did Not Fire
    183      * 1 = Flash Fired
    184      */
    185     public static final int TAG_CANON_STATE1_FLASH_ACTIVITY = 0xC11C;
    186     public static final int TAG_CANON_STATE1_FLASH_DETAILS = 0xC11D;
    187     public static final int TAG_CANON_STATE1_UNKNOWN_12 = 0xC11E;
    188     public static final int TAG_CANON_STATE1_UNKNOWN_13 = 0xC11F;
    189     /**
    190      * 0 = Focus Mode: Single
    191      * 1 = Focus Mode: Continuous
    192      */
    193     public static final int TAG_CANON_STATE1_FOCUS_MODE_2 = 0xC120;
    194 
    195     /**
    196      * 0 = Auto
    197      * 1 = Sunny
    198      * 2 = Cloudy
    199      * 3 = Tungsten
    200      * 4 = Flourescent
    201      * 5 = Flash
    202      * 6 = Custom
    203      */
    204     public static final int TAG_CANON_STATE2_WHITE_BALANCE = 0xC207;
    205     public static final int TAG_CANON_STATE2_SEQUENCE_NUMBER = 0xC209;
    206     public static final int TAG_CANON_STATE2_AF_POINT_USED = 0xC20E;
    207     /**
    208      * The value of this tag may be translated into a flash bias value, in EV.
    209      *
    210      * 0xffc0 = -2 EV
    211      * 0xffcc = -1.67 EV
    212      * 0xffd0 = -1.5 EV
    213      * 0xffd4 = -1.33 EV
    214      * 0xffe0 = -1 EV
    215      * 0xffec = -0.67 EV
    216      * 0xfff0 = -0.5 EV
    217      * 0xfff4 = -0.33 EV
    218      * 0x0000 = 0 EV
    219      * 0x000c = 0.33 EV
    220      * 0x0010 = 0.5 EV
    221      * 0x0014 = 0.67 EV
    222      * 0x0020 = 1 EV
    223      * 0x002c = 1.33 EV
    224      * 0x0030 = 1.5 EV
    225      * 0x0034 = 1.67 EV
    226      * 0x0040 = 2 EV
    227      */
    228     public static final int TAG_CANON_STATE2_FLASH_BIAS = 0xC20F;
    229     public static final int TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING = 0xC210;
    230     public static final int TAG_CANON_STATE2_AEB_BRACKET_VALUE = 0xC211;
    231     public static final int TAG_CANON_STATE2_SUBJECT_DISTANCE = 0xC213;
    232 
    233     /**
    234      * Long Exposure Noise Reduction
    235      * 0 = Off
    236      * 1 = On
    237      */
    238     public static final int TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION = 0xC301;
    239 
    240     /**
    241      * Shutter/Auto Exposure-lock buttons
    242      * 0 = AF/AE lock
    243      * 1 = AE lock/AF
    244      * 2 = AF/AF lock
    245      * 3 = AE+release/AE+AF
    246      */
    247     public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS = 0xC302;
    248 
    249     /**
    250      * Mirror lockup
    251      * 0 = Disable
    252      * 1 = Enable
    253      */
    254     public static final int TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP = 0xC303;
    255 
    256     /**
    257      * Tv/Av and exposure level
    258      * 0 = 1/2 stop
    259      * 1 = 1/3 stop
    260      */
    261     public static final int TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL = 0xC304;
    262 
    263     /**
    264      * AF-assist light
    265      * 0 = On (Auto)
    266      * 1 = Off
    267      */
    268     public static final int TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT = 0xC305;
    269 
    270     /**
    271      * Shutter speed in Av mode
    272      * 0 = Automatic
    273      * 1 = 1/200 (fixed)
    274      */
    275     public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE = 0xC306;
    276 
    277     /**
    278      * Auto-Exposure Bracketting sequence/auto cancellation
    279      * 0 = 0,-,+ / Enabled
    280      * 1 = 0,-,+ / Disabled
    281      * 2 = -,0,+ / Enabled
    282      * 3 = -,0,+ / Disabled
    283      */
    284     public static final int TAG_CANON_CUSTOM_FUNCTION_BRACKETTING = 0xC307;
    285 
    286     /**
    287      * Shutter Curtain Sync
    288      * 0 = 1st Curtain Sync
    289      * 1 = 2nd Curtain Sync
    290      */
    291     public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC = 0xC308;
    292 
    293     /**
    294      * Lens Auto-Focus stop button Function Switch
    295      * 0 = AF stop
    296      * 1 = Operate AF
    297      * 2 = Lock AE and start timer
    298      */
    299     public static final int TAG_CANON_CUSTOM_FUNCTION_AF_STOP = 0xC309;
    300 
    301     /**
    302      * Auto reduction of fill flash
    303      * 0 = Enable
    304      * 1 = Disable
    305      */
    306     public static final int TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION = 0xC30A;
    307 
    308     /**
    309      * Menu button return position
    310      * 0 = Top
    311      * 1 = Previous (volatile)
    312      * 2 = Previous
    313      */
    314     public static final int TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN = 0xC30B;
    315 
    316     /**
    317      * SET button function when shooting
    318      * 0 = Not Assigned
    319      * 1 = Change Quality
    320      * 2 = Change ISO Speed
    321      * 3 = Select Parameters
    322      */
    323     public static final int TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION = 0xC30C;
    324 
    325     /**
    326      * Sensor cleaning
    327      * 0 = Disable
    328      * 1 = Enable
    329      */
    330     public static final int TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING = 0xC30D;
     39    // These TAG_*_ARRAY Exif tags map to arrays of int16 values which are split out into separate 'fake' tags.
     40    // When an attempt is made to set one of these on the directory, it is split and the corresponding offset added to the tagType.
     41    // So the resulting tag is the offset + the index into the array.
     42
     43    private static final int TAG_CAMERA_SETTINGS_ARRAY  = 0x0001;
     44    private static final int TAG_FOCAL_LENGTH_ARRAY = 0x0002;
     45    private static final int TAG_SHOT_INFO_ARRAY = 0x0004;
     46    private static final int TAG_PANORAMA_ARRAY = 0x0005;
     47
     48    public static final int TAG_CANON_IMAGE_TYPE            = 0x0006;
     49    public static final int TAG_CANON_FIRMWARE_VERSION      = 0x0007;
     50    public static final int TAG_CANON_IMAGE_NUMBER          = 0x0008;
     51    public static final int TAG_CANON_OWNER_NAME            = 0x0009;
     52    public static final int TAG_CANON_SERIAL_NUMBER         = 0x000C;
     53    public static final int TAG_CAMERA_INFO_ARRAY           = 0x000D; // depends upon model, so leave for now
     54    public static final int TAG_CANON_FILE_LENGTH           = 0x000E;
     55    public static final int TAG_CANON_CUSTOM_FUNCTIONS_ARRAY = 0x000F; // depends upon model, so leave for now
     56    public static final int TAG_MODEL_ID                    = 0x0010;
     57    public static final int TAG_MOVIE_INFO_ARRAY            = 0x0011; // not currently decoded as not sure we see it in still images
     58    private static final int TAG_AF_INFO_ARRAY              = 0x0012; // not currently decoded
     59    public static final int TAG_THUMBNAIL_IMAGE_VALID_AREA  = 0x0013;
     60    public static final int TAG_SERIAL_NUMBER_FORMAT        = 0x0015;
     61    public static final int TAG_SUPER_MACRO                 = 0x001A;
     62    public static final int TAG_DATE_STAMP_MODE             = 0x001C;
     63    public static final int TAG_MY_COLORS                   = 0x001D;
     64    public static final int TAG_FIRMWARE_REVISION           = 0x001E;
     65    public static final int TAG_CATEGORIES                  = 0x0023;
     66    public static final int TAG_FACE_DETECT_ARRAY_1         = 0x0024;
     67    public static final int TAG_FACE_DETECT_ARRAY_2         = 0x0025;
     68    public static final int TAG_AF_INFO_ARRAY_2             = 0x0026;
     69    public static final int TAG_IMAGE_UNIQUE_ID             = 0x0028;
     70    public static final int TAG_RAW_DATA_OFFSET             = 0x0081;
     71    public static final int TAG_ORIGINAL_DECISION_DATA_OFFSET = 0x0083;
     72    public static final int TAG_CUSTOM_FUNCTIONS_1D_ARRAY   = 0x0090; // not currently decoded
     73    public static final int TAG_PERSONAL_FUNCTIONS_ARRAY    = 0x0091; // not currently decoded
     74    public static final int TAG_PERSONAL_FUNCTION_VALUES_ARRAY = 0x0092; // not currently decoded
     75    public static final int TAG_FILE_INFO_ARRAY             = 0x0093; // not currently decoded
     76    public static final int TAG_AF_POINTS_IN_FOCUS_1D       = 0x0094;
     77    public static final int TAG_LENS_MODEL                  = 0x0095;
     78    public static final int TAG_SERIAL_INFO_ARRAY           = 0x0096; // not currently decoded
     79    public static final int TAG_DUST_REMOVAL_DATA           = 0x0097;
     80    public static final int TAG_CROP_INFO                   = 0x0098; // not currently decoded
     81    public static final int TAG_CUSTOM_FUNCTIONS_ARRAY_2    = 0x0099; // not currently decoded
     82    public static final int TAG_ASPECT_INFO_ARRAY           = 0x009A; // not currently decoded
     83    public static final int TAG_PROCESSING_INFO_ARRAY       = 0x00A0; // not currently decoded
     84    public static final int TAG_TONE_CURVE_TABLE            = 0x00A1;
     85    public static final int TAG_SHARPNESS_TABLE             = 0x00A2;
     86    public static final int TAG_SHARPNESS_FREQ_TABLE        = 0x00A3;
     87    public static final int TAG_WHITE_BALANCE_TABLE         = 0x00A4;
     88    public static final int TAG_COLOR_BALANCE_ARRAY         = 0x00A9; // not currently decoded
     89    public static final int TAG_MEASURED_COLOR_ARRAY        = 0x00AA; // not currently decoded
     90    public static final int TAG_COLOR_TEMPERATURE           = 0x00AE;
     91    public static final int TAG_CANON_FLAGS_ARRAY           = 0x00B0; // not currently decoded
     92    public static final int TAG_MODIFIED_INFO_ARRAY         = 0x00B1; // not currently decoded
     93    public static final int TAG_TONE_CURVE_MATCHING         = 0x00B2;
     94    public static final int TAG_WHITE_BALANCE_MATCHING      = 0x00B3;
     95    public static final int TAG_COLOR_SPACE                 = 0x00B4;
     96    public static final int TAG_PREVIEW_IMAGE_INFO_ARRAY    = 0x00B6; // not currently decoded
     97    public static final int TAG_VRD_OFFSET                  = 0x00D0;
     98    public static final int TAG_SENSOR_INFO_ARRAY           = 0x00E0; // not currently decoded
     99    public static final int TAG_COLOR_DATA_ARRAY_2 = 0x4001; // depends upon camera model, not currently decoded
     100    public static final int TAG_COLOR_INFO_ARRAY_2          = 0x4003; // not currently decoded
     101    public static final int TAG_CUSTOM_PICTURE_STYLE_FILE_NAME = 0x4010;
     102    public static final int TAG_COLOR_INFO_ARRAY            = 0x4013; // not currently decoded
     103    public static final int TAG_VIGNETTING_CORRECTION_ARRAY_1 = 0x4015; // not currently decoded
     104    public static final int TAG_VIGNETTING_CORRECTION_ARRAY_2 = 0x4016; // not currently decoded
     105    public static final int TAG_LIGHTING_OPTIMIZER_ARRAY = 0x4018; // not currently decoded
     106    public static final int TAG_LENS_INFO_ARRAY             = 0x4019; // not currently decoded
     107    public static final int TAG_AMBIANCE_INFO_ARRAY         = 0x4020; // not currently decoded
     108    public static final int TAG_FILTER_INFO_ARRAY           = 0x4024; // not currently decoded
     109
     110    public final static class CameraSettings
     111    {
     112        // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
     113        private static final int OFFSET = 0xC100;
     114
     115        /**
     116         * 1 = Macro
     117         * 2 = Normal
     118         */
     119        public static final int TAG_MACRO_MODE = OFFSET + 0x01;
     120        public static final int TAG_SELF_TIMER_DELAY = OFFSET + 0x02;
     121        /**
     122         * 2 = Normal
     123         * 3 = Fine
     124         * 5 = Superfine
     125         */
     126        public static final int TAG_QUALITY = OFFSET + 0x03;
     127        /**
     128         * 0 = Flash Not Fired
     129         * 1 = Auto
     130         * 2 = On
     131         * 3 = Red Eye Reduction
     132         * 4 = Slow Synchro
     133         * 5 = Auto + Red Eye Reduction
     134         * 6 = On + Red Eye Reduction
     135         * 16 = External Flash
     136         */
     137        public static final int TAG_FLASH_MODE = OFFSET + 0x04;
     138        /**
     139         * 0 = Single Frame or Timer Mode
     140         * 1 = Continuous
     141         */
     142        public static final int TAG_CONTINUOUS_DRIVE_MODE = OFFSET + 0x05;
     143        public static final int TAG_UNKNOWN_2 = OFFSET + 0x06;
     144        /**
     145         * 0 = One-Shot
     146         * 1 = AI Servo
     147         * 2 = AI Focus
     148         * 3 = Manual Focus
     149         * 4 = Single
     150         * 5 = Continuous
     151         * 6 = Manual Focus
     152         */
     153        public static final int TAG_FOCUS_MODE_1 = OFFSET + 0x07;
     154        public static final int TAG_UNKNOWN_3 = OFFSET + 0x08;
     155        public static final int TAG_UNKNOWN_4 = OFFSET + 0x09;
     156        /**
     157         * 0 = Large
     158         * 1 = Medium
     159         * 2 = Small
     160         */
     161        public static final int TAG_IMAGE_SIZE = OFFSET + 0x0A;
     162        /**
     163         * 0 = Full Auto
     164         * 1 = Manual
     165         * 2 = Landscape
     166         * 3 = Fast Shutter
     167         * 4 = Slow Shutter
     168         * 5 = Night
     169         * 6 = Black & White
     170         * 7 = Sepia
     171         * 8 = Portrait
     172         * 9 = Sports
     173         * 10 = Macro / Close-Up
     174         * 11 = Pan Focus
     175         */
     176        public static final int TAG_EASY_SHOOTING_MODE = OFFSET + 0x0B;
     177        /**
     178         * 0 = No Digital Zoom
     179         * 1 = 2x
     180         * 2 = 4x
     181         */
     182        public static final int TAG_DIGITAL_ZOOM = OFFSET + 0x0C;
     183        /**
     184         * 0 = Normal
     185         * 1 = High
     186         * 65535 = Low
     187         */
     188        public static final int TAG_CONTRAST = OFFSET + 0x0D;
     189        /**
     190         * 0 = Normal
     191         * 1 = High
     192         * 65535 = Low
     193         */
     194        public static final int TAG_SATURATION = OFFSET + 0x0E;
     195        /**
     196         * 0 = Normal
     197         * 1 = High
     198         * 65535 = Low
     199         */
     200        public static final int TAG_SHARPNESS = OFFSET + 0x0F;
     201        /**
     202         * 0 = Check ISOSpeedRatings EXIF tag for ISO Speed
     203         * 15 = Auto ISO
     204         * 16 = ISO 50
     205         * 17 = ISO 100
     206         * 18 = ISO 200
     207         * 19 = ISO 400
     208         */
     209        public static final int TAG_ISO = OFFSET + 0x10;
     210        /**
     211         * 3 = Evaluative
     212         * 4 = Partial
     213         * 5 = Centre Weighted
     214         */
     215        public static final int TAG_METERING_MODE = OFFSET + 0x11;
     216        /**
     217         * 0 = Manual
     218         * 1 = Auto
     219         * 3 = Close-up (Macro)
     220         * 8 = Locked (Pan Mode)
     221         */
     222        public static final int TAG_FOCUS_TYPE = OFFSET + 0x12;
     223        /**
     224         * 12288 = None (Manual Focus)
     225         * 12289 = Auto Selected
     226         * 12290 = Right
     227         * 12291 = Centre
     228         * 12292 = Left
     229         */
     230        public static final int TAG_AF_POINT_SELECTED = OFFSET + 0x13;
     231        /**
     232         * 0 = Easy Shooting (See Easy Shooting Mode)
     233         * 1 = Program
     234         * 2 = Tv-Priority
     235         * 3 = Av-Priority
     236         * 4 = Manual
     237         * 5 = A-DEP
     238         */
     239        public static final int TAG_EXPOSURE_MODE = OFFSET + 0x14;
     240        public static final int TAG_UNKNOWN_7 = OFFSET + 0x15;
     241        public static final int TAG_UNKNOWN_8 = OFFSET + 0x16;
     242        public static final int TAG_LONG_FOCAL_LENGTH = OFFSET + 0x17;
     243        public static final int TAG_SHORT_FOCAL_LENGTH = OFFSET + 0x18;
     244        public static final int TAG_FOCAL_UNITS_PER_MM = OFFSET + 0x19;
     245        public static final int TAG_UNKNOWN_9 = OFFSET + 0x1A;
     246        public static final int TAG_UNKNOWN_10 = OFFSET + 0x1B;
     247        /**
     248         * 0 = Flash Did Not Fire
     249         * 1 = Flash Fired
     250         */
     251        public static final int TAG_FLASH_ACTIVITY = OFFSET + 0x1C;
     252        public static final int TAG_FLASH_DETAILS = OFFSET + 0x1D;
     253        public static final int TAG_UNKNOWN_12 = OFFSET + 0x1E;
     254        public static final int TAG_UNKNOWN_13 = OFFSET + 0x1F;
     255        /**
     256         * 0 = Focus Mode: Single
     257         * 1 = Focus Mode: Continuous
     258         */
     259        public static final int TAG_FOCUS_MODE_2 = OFFSET + 0x20;
     260    }
     261   
     262    public final static class FocalLength
     263    {
     264        // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
     265
     266        private static final int OFFSET = 0xC200;
     267       
     268        /**
     269         * 0 = Auto
     270         * 1 = Sunny
     271         * 2 = Cloudy
     272         * 3 = Tungsten
     273         * 4 = Florescent
     274         * 5 = Flash
     275         * 6 = Custom
     276         */
     277        public static final int TAG_WHITE_BALANCE = OFFSET + 0x07;
     278        public static final int TAG_SEQUENCE_NUMBER = OFFSET + 0x09;
     279        public static final int TAG_AF_POINT_USED = OFFSET + 0x0E;
     280        /**
     281         * The value of this tag may be translated into a flash bias value, in EV.
     282         *
     283         * 0xffc0 = -2 EV
     284         * 0xffcc = -1.67 EV
     285         * 0xffd0 = -1.5 EV
     286         * 0xffd4 = -1.33 EV
     287         * 0xffe0 = -1 EV
     288         * 0xffec = -0.67 EV
     289         * 0xfff0 = -0.5 EV
     290         * 0xfff4 = -0.33 EV
     291         * 0x0000 = 0 EV
     292         * 0x000c = 0.33 EV
     293         * 0x0010 = 0.5 EV
     294         * 0x0014 = 0.67 EV
     295         * 0x0020 = 1 EV
     296         * 0x002c = 1.33 EV
     297         * 0x0030 = 1.5 EV
     298         * 0x0034 = 1.67 EV
     299         * 0x0040 = 2 EV
     300         */
     301        public static final int TAG_FLASH_BIAS = OFFSET + 0x0F;
     302        public static final int TAG_AUTO_EXPOSURE_BRACKETING = OFFSET + 0x10;
     303        public static final int TAG_AEB_BRACKET_VALUE = OFFSET + 0x11;
     304        public static final int TAG_SUBJECT_DISTANCE = OFFSET + 0x13;
     305    }
     306   
     307    public final static class ShotInfo
     308    {
     309        // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
     310
     311        private static final int OFFSET = 0xC400;
     312
     313        public static final int TAG_AUTO_ISO = OFFSET + 1;
     314        public static final int TAG_BASE_ISO = OFFSET + 2;
     315        public static final int TAG_MEASURED_EV = OFFSET + 3;
     316        public static final int TAG_TARGET_APERTURE = OFFSET + 4;
     317        public static final int TAG_TARGET_EXPOSURE_TIME = OFFSET + 5;
     318        public static final int TAG_EXPOSURE_COMPENSATION = OFFSET + 6;
     319        public static final int TAG_WHITE_BALANCE = OFFSET + 7;
     320        public static final int TAG_SLOW_SHUTTER = OFFSET + 8;
     321        public static final int TAG_SEQUENCE_NUMBER = OFFSET + 9;
     322        public static final int TAG_OPTICAL_ZOOM_CODE = OFFSET + 10;
     323        public static final int TAG_CAMERA_TEMPERATURE = OFFSET + 12;
     324        public static final int TAG_FLASH_GUIDE_NUMBER = OFFSET + 13;
     325        public static final int TAG_AF_POINTS_IN_FOCUS = OFFSET + 14;
     326        public static final int TAG_FLASH_EXPOSURE_BRACKETING = OFFSET + 15;
     327        public static final int TAG_AUTO_EXPOSURE_BRACKETING = OFFSET + 16;
     328        public static final int TAG_AEB_BRACKET_VALUE = OFFSET + 17;
     329        public static final int TAG_CONTROL_MODE = OFFSET + 18;
     330        public static final int TAG_FOCUS_DISTANCE_UPPER = OFFSET + 19;
     331        public static final int TAG_FOCUS_DISTANCE_LOWER = OFFSET + 20;
     332        public static final int TAG_F_NUMBER = OFFSET + 21;
     333        public static final int TAG_EXPOSURE_TIME = OFFSET + 22;
     334        public static final int TAG_MEASURED_EV_2 = OFFSET + 23;
     335        public static final int TAG_BULB_DURATION = OFFSET + 24;
     336        public static final int TAG_CAMERA_TYPE = OFFSET + 26;
     337        public static final int TAG_AUTO_ROTATE = OFFSET + 27;
     338        public static final int TAG_ND_FILTER = OFFSET + 28;
     339        public static final int TAG_SELF_TIMER_2 = OFFSET + 29;
     340        public static final int TAG_FLASH_OUTPUT = OFFSET + 33;
     341    }
     342
     343    public final static class Panorama
     344    {
     345        // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
     346
     347        private static final int OFFSET = 0xC500;
     348
     349        public static final int TAG_PANORAMA_FRAME_NUMBER = OFFSET + 2;
     350        public static final int TAG_PANORAMA_DIRECTION = OFFSET + 5;
     351    }
     352
     353    public final static class AFInfo
     354    {
     355        // These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
     356
     357        private static final int OFFSET = 0xD200;
     358
     359        public static final int TAG_NUM_AF_POINTS = OFFSET;
     360        public static final int TAG_VALID_AF_POINTS = OFFSET + 1;
     361        public static final int TAG_IMAGE_WIDTH = OFFSET + 2;
     362        public static final int TAG_IMAGE_HEIGHT = OFFSET + 3;
     363        public static final int TAG_AF_IMAGE_WIDTH = OFFSET + 4;
     364        public static final int TAG_AF_IMAGE_HEIGHT = OFFSET + 5;
     365        public static final int TAG_AF_AREA_WIDTH = OFFSET + 6;
     366        public static final int TAG_AF_AREA_HEIGHT = OFFSET + 7;
     367        public static final int TAG_AF_AREA_X_POSITIONS = OFFSET + 8;
     368        public static final int TAG_AF_AREA_Y_POSITIONS = OFFSET + 9;
     369        public static final int TAG_AF_POINTS_IN_FOCUS = OFFSET + 10;
     370        public static final int TAG_PRIMARY_AF_POINT_1 = OFFSET + 11;
     371        public static final int TAG_PRIMARY_AF_POINT_2 = OFFSET + 12; // not sure why there are two of these
     372    }
     373
     374//    /**
     375//     * Long Exposure Noise Reduction
     376//     * 0 = Off
     377//     * 1 = On
     378//     */
     379//    public static final int TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION = 0xC301;
     380//
     381//    /**
     382//     * Shutter/Auto Exposure-lock buttons
     383//     * 0 = AF/AE lock
     384//     * 1 = AE lock/AF
     385//     * 2 = AF/AF lock
     386//     * 3 = AE+release/AE+AF
     387//     */
     388//    public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS = 0xC302;
     389//
     390//    /**
     391//     * Mirror lockup
     392//     * 0 = Disable
     393//     * 1 = Enable
     394//     */
     395//    public static final int TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP = 0xC303;
     396//
     397//    /**
     398//     * Tv/Av and exposure level
     399//     * 0 = 1/2 stop
     400//     * 1 = 1/3 stop
     401//     */
     402//    public static final int TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL = 0xC304;
     403//
     404//    /**
     405//     * AF-assist light
     406//     * 0 = On (Auto)
     407//     * 1 = Off
     408//     */
     409//    public static final int TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT = 0xC305;
     410//
     411//    /**
     412//     * Shutter speed in Av mode
     413//     * 0 = Automatic
     414//     * 1 = 1/200 (fixed)
     415//     */
     416//    public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE = 0xC306;
     417//
     418//    /**
     419//     * Auto-Exposure Bracketting sequence/auto cancellation
     420//     * 0 = 0,-,+ / Enabled
     421//     * 1 = 0,-,+ / Disabled
     422//     * 2 = -,0,+ / Enabled
     423//     * 3 = -,0,+ / Disabled
     424//     */
     425//    public static final int TAG_CANON_CUSTOM_FUNCTION_BRACKETTING = 0xC307;
     426//
     427//    /**
     428//     * Shutter Curtain Sync
     429//     * 0 = 1st Curtain Sync
     430//     * 1 = 2nd Curtain Sync
     431//     */
     432//    public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC = 0xC308;
     433//
     434//    /**
     435//     * Lens Auto-Focus stop button Function Switch
     436//     * 0 = AF stop
     437//     * 1 = Operate AF
     438//     * 2 = Lock AE and start timer
     439//     */
     440//    public static final int TAG_CANON_CUSTOM_FUNCTION_AF_STOP = 0xC309;
     441//
     442//    /**
     443//     * Auto reduction of fill flash
     444//     * 0 = Enable
     445//     * 1 = Disable
     446//     */
     447//    public static final int TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION = 0xC30A;
     448//
     449//    /**
     450//     * Menu button return position
     451//     * 0 = Top
     452//     * 1 = Previous (volatile)
     453//     * 2 = Previous
     454//     */
     455//    public static final int TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN = 0xC30B;
     456//
     457//    /**
     458//     * SET button function when shooting
     459//     * 0 = Not Assigned
     460//     * 1 = Change Quality
     461//     * 2 = Change ISO Speed
     462//     * 3 = Select Parameters
     463//     */
     464//    public static final int TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION = 0xC30C;
     465//
     466//    /**
     467//     * Sensor cleaning
     468//     * 0 = Disable
     469//     * 1 = Enable
     470//     */
     471//    public static final int TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING = 0xC30D;
    331472
    332473    // 9  A  B  C  D  E  F  10 11 12 13
    333474    // 9  10 11 12 13 14 15 16 17 18 19
    334     protected static final HashMap _tagNameMap = new HashMap();
     475    @NotNull
     476    protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
    335477
    336478    static
    337479    {
    338         _tagNameMap.put(new Integer(TAG_CANON_FIRMWARE_VERSION), "Firmware Version");
    339         _tagNameMap.put(new Integer(TAG_CANON_IMAGE_NUMBER), "Image Number");
    340         _tagNameMap.put(new Integer(TAG_CANON_IMAGE_TYPE), "Image Type");
    341         _tagNameMap.put(new Integer(TAG_CANON_OWNER_NAME), "Owner Name");
    342         _tagNameMap.put(new Integer(TAG_CANON_UNKNOWN_1), "Makernote Unknown 1");
    343         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTIONS), "Custom Functions");
    344         _tagNameMap.put(new Integer(TAG_CANON_SERIAL_NUMBER), "Camera Serial Number");
    345         _tagNameMap.put(new Integer(TAG_CANON_STATE1_AF_POINT_SELECTED), "AF Point Selected");
    346         _tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE), "Continuous Drive Mode");
    347         _tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTRAST), "Contrast");
    348         _tagNameMap.put(new Integer(TAG_CANON_STATE1_EASY_SHOOTING_MODE), "Easy Shooting Mode");
    349         _tagNameMap.put(new Integer(TAG_CANON_STATE1_EXPOSURE_MODE), "Exposure Mode");
    350         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_DETAILS), "Flash Details");
    351         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_MODE), "Flash Mode");
    352         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCAL_UNITS_PER_MM), "Focal Units per mm");
    353         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_1), "Focus Mode");
    354         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_2), "Focus Mode");
    355         _tagNameMap.put(new Integer(TAG_CANON_STATE1_IMAGE_SIZE), "Image Size");
    356         _tagNameMap.put(new Integer(TAG_CANON_STATE1_ISO), "Iso");
    357         _tagNameMap.put(new Integer(TAG_CANON_STATE1_LONG_FOCAL_LENGTH), "Long Focal Length");
    358         _tagNameMap.put(new Integer(TAG_CANON_STATE1_MACRO_MODE), "Macro Mode");
    359         _tagNameMap.put(new Integer(TAG_CANON_STATE1_METERING_MODE), "Metering Mode");
    360         _tagNameMap.put(new Integer(TAG_CANON_STATE1_SATURATION), "Saturation");
    361         _tagNameMap.put(new Integer(TAG_CANON_STATE1_SELF_TIMER_DELAY), "Self Timer Delay");
    362         _tagNameMap.put(new Integer(TAG_CANON_STATE1_SHARPNESS), "Sharpness");
    363         _tagNameMap.put(new Integer(TAG_CANON_STATE1_SHORT_FOCAL_LENGTH), "Short Focal Length");
    364         _tagNameMap.put(new Integer(TAG_CANON_STATE1_QUALITY), "Quality");
    365         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_2), "Unknown Camera State 2");
    366         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_3), "Unknown Camera State 3");
    367         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_4), "Unknown Camera State 4");
    368         _tagNameMap.put(new Integer(TAG_CANON_STATE1_DIGITAL_ZOOM), "Digital Zoom");
    369         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_TYPE), "Focus Type");
    370         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_7), "Unknown Camera State 7");
    371         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_8), "Unknown Camera State 8");
    372         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_9), "Unknown Camera State 9");
    373         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_10), "Unknown Camera State 10");
    374         _tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_ACTIVITY), "Flash Activity");
    375         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_12), "Unknown Camera State 12");
    376         _tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_13), "Unknown Camera State 13");
    377         _tagNameMap.put(new Integer(TAG_CANON_STATE2_WHITE_BALANCE), "White Balance");
    378         _tagNameMap.put(new Integer(TAG_CANON_STATE2_SEQUENCE_NUMBER), "Sequence Number");
    379         _tagNameMap.put(new Integer(TAG_CANON_STATE2_AF_POINT_USED), "AF Point Used");
    380         _tagNameMap.put(new Integer(TAG_CANON_STATE2_FLASH_BIAS), "Flash Bias");
    381         _tagNameMap.put(new Integer(TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING), "Auto Exposure Bracketing");
    382         _tagNameMap.put(new Integer(TAG_CANON_STATE2_AEB_BRACKET_VALUE), "AEB Bracket Value");
    383         _tagNameMap.put(new Integer(TAG_CANON_STATE2_SUBJECT_DISTANCE), "Subject Distance");
    384 
    385         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION), "Long Exposure Noise Reduction");
    386         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS), "Shutter/Auto Exposure-lock Buttons");
    387         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP), "Mirror Lockup");
    388         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL), "Tv/Av And Exposure Level");
    389         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT), "AF-Assist Light");
    390         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE), "Shutter Speed in Av Mode");
    391         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_BRACKETTING), "Auto-Exposure Bracketting Sequence/Auto Cancellation");
    392         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC), "Shutter Curtain Sync");
    393         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_STOP), "Lens Auto-Focus Stop Button Function Switch");
    394         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION), "Auto Reduction of Fill Flash");
    395         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN), "Menu Button Return Position");
    396         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION), "SET Button Function When Shooting");
    397         _tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING), "Sensor Cleaning");
     480        _tagNameMap.put(TAG_CANON_FIRMWARE_VERSION, "Firmware Version");
     481        _tagNameMap.put(TAG_CANON_IMAGE_NUMBER, "Image Number");
     482        _tagNameMap.put(TAG_CANON_IMAGE_TYPE, "Image Type");
     483        _tagNameMap.put(TAG_CANON_OWNER_NAME, "Owner Name");
     484        _tagNameMap.put(TAG_CANON_SERIAL_NUMBER, "Camera Serial Number");
     485        _tagNameMap.put(TAG_CAMERA_INFO_ARRAY, "Camera Info Array");
     486        _tagNameMap.put(TAG_CANON_FILE_LENGTH, "File Length");
     487        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTIONS_ARRAY, "Custom Functions");
     488        _tagNameMap.put(TAG_MODEL_ID, "Canon Model ID");
     489        _tagNameMap.put(TAG_MOVIE_INFO_ARRAY, "Movie Info Array");
     490
     491        _tagNameMap.put(CameraSettings.TAG_AF_POINT_SELECTED, "AF Point Selected");
     492        _tagNameMap.put(CameraSettings.TAG_CONTINUOUS_DRIVE_MODE, "Continuous Drive Mode");
     493        _tagNameMap.put(CameraSettings.TAG_CONTRAST, "Contrast");
     494        _tagNameMap.put(CameraSettings.TAG_EASY_SHOOTING_MODE, "Easy Shooting Mode");
     495        _tagNameMap.put(CameraSettings.TAG_EXPOSURE_MODE, "Exposure Mode");
     496        _tagNameMap.put(CameraSettings.TAG_FLASH_DETAILS, "Flash Details");
     497        _tagNameMap.put(CameraSettings.TAG_FLASH_MODE, "Flash Mode");
     498        _tagNameMap.put(CameraSettings.TAG_FOCAL_UNITS_PER_MM, "Focal Units per mm");
     499        _tagNameMap.put(CameraSettings.TAG_FOCUS_MODE_1, "Focus Mode");
     500        _tagNameMap.put(CameraSettings.TAG_FOCUS_MODE_2, "Focus Mode");
     501        _tagNameMap.put(CameraSettings.TAG_IMAGE_SIZE, "Image Size");
     502        _tagNameMap.put(CameraSettings.TAG_ISO, "Iso");
     503        _tagNameMap.put(CameraSettings.TAG_LONG_FOCAL_LENGTH, "Long Focal Length");
     504        _tagNameMap.put(CameraSettings.TAG_MACRO_MODE, "Macro Mode");
     505        _tagNameMap.put(CameraSettings.TAG_METERING_MODE, "Metering Mode");
     506        _tagNameMap.put(CameraSettings.TAG_SATURATION, "Saturation");
     507        _tagNameMap.put(CameraSettings.TAG_SELF_TIMER_DELAY, "Self Timer Delay");
     508        _tagNameMap.put(CameraSettings.TAG_SHARPNESS, "Sharpness");
     509        _tagNameMap.put(CameraSettings.TAG_SHORT_FOCAL_LENGTH, "Short Focal Length");
     510        _tagNameMap.put(CameraSettings.TAG_QUALITY, "Quality");
     511        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_2, "Unknown Camera Setting 2");
     512        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_3, "Unknown Camera Setting 3");
     513        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_4, "Unknown Camera Setting 4");
     514        _tagNameMap.put(CameraSettings.TAG_DIGITAL_ZOOM, "Digital Zoom");
     515        _tagNameMap.put(CameraSettings.TAG_FOCUS_TYPE, "Focus Type");
     516        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_7, "Unknown Camera Setting 7");
     517        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_8, "Unknown Camera Setting 8");
     518        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_9, "Unknown Camera Setting 9");
     519        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_10, "Unknown Camera Setting 10");
     520        _tagNameMap.put(CameraSettings.TAG_FLASH_ACTIVITY, "Flash Activity");
     521        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_12, "Unknown Camera Setting 12");
     522        _tagNameMap.put(CameraSettings.TAG_UNKNOWN_13, "Unknown Camera Setting 13");
     523
     524        _tagNameMap.put(FocalLength.TAG_WHITE_BALANCE, "White Balance");
     525        _tagNameMap.put(FocalLength.TAG_SEQUENCE_NUMBER, "Sequence Number");
     526        _tagNameMap.put(FocalLength.TAG_AF_POINT_USED, "AF Point Used");
     527        _tagNameMap.put(FocalLength.TAG_FLASH_BIAS, "Flash Bias");
     528        _tagNameMap.put(FocalLength.TAG_AUTO_EXPOSURE_BRACKETING, "Auto Exposure Bracketing");
     529        _tagNameMap.put(FocalLength.TAG_AEB_BRACKET_VALUE, "AEB Bracket Value");
     530        _tagNameMap.put(FocalLength.TAG_SUBJECT_DISTANCE, "Subject Distance");
     531
     532        _tagNameMap.put(ShotInfo.TAG_AUTO_ISO, "Auto ISO");
     533        _tagNameMap.put(ShotInfo.TAG_BASE_ISO, "Base ISO");
     534        _tagNameMap.put(ShotInfo.TAG_MEASURED_EV, "Measured EV");
     535        _tagNameMap.put(ShotInfo.TAG_TARGET_APERTURE, "Target Aperture");
     536        _tagNameMap.put(ShotInfo.TAG_TARGET_EXPOSURE_TIME, "Target Exposure Time");
     537        _tagNameMap.put(ShotInfo.TAG_EXPOSURE_COMPENSATION, "Exposure Compensation");
     538        _tagNameMap.put(ShotInfo.TAG_WHITE_BALANCE, "White Balance");
     539        _tagNameMap.put(ShotInfo.TAG_SLOW_SHUTTER, "Slow Shutter");
     540        _tagNameMap.put(ShotInfo.TAG_SEQUENCE_NUMBER, "Sequence Number");
     541        _tagNameMap.put(ShotInfo.TAG_OPTICAL_ZOOM_CODE, "Optical Zoom Code");
     542        _tagNameMap.put(ShotInfo.TAG_CAMERA_TEMPERATURE, "Camera Temperature");
     543        _tagNameMap.put(ShotInfo.TAG_FLASH_GUIDE_NUMBER, "Flash Guide Number");
     544        _tagNameMap.put(ShotInfo.TAG_AF_POINTS_IN_FOCUS, "AF Points in Focus");
     545        _tagNameMap.put(ShotInfo.TAG_FLASH_EXPOSURE_BRACKETING, "Flash Exposure Compensation");
     546        _tagNameMap.put(ShotInfo.TAG_AUTO_EXPOSURE_BRACKETING, "Auto Exposure Bracketing");
     547        _tagNameMap.put(ShotInfo.TAG_AEB_BRACKET_VALUE, "AEB Bracket Value");
     548        _tagNameMap.put(ShotInfo.TAG_CONTROL_MODE, "Control Mode");
     549        _tagNameMap.put(ShotInfo.TAG_FOCUS_DISTANCE_UPPER, "Focus Distance Upper");
     550        _tagNameMap.put(ShotInfo.TAG_FOCUS_DISTANCE_LOWER, "Focus Distance Lower");
     551        _tagNameMap.put(ShotInfo.TAG_F_NUMBER, "F Number");
     552        _tagNameMap.put(ShotInfo.TAG_EXPOSURE_TIME, "Exposure Time");
     553        _tagNameMap.put(ShotInfo.TAG_MEASURED_EV_2, "Measured EV 2");
     554        _tagNameMap.put(ShotInfo.TAG_BULB_DURATION, "Bulb Duration");
     555        _tagNameMap.put(ShotInfo.TAG_CAMERA_TYPE, "Camera Type");
     556        _tagNameMap.put(ShotInfo.TAG_AUTO_ROTATE, "Auto Rotate");
     557        _tagNameMap.put(ShotInfo.TAG_ND_FILTER, "ND Filter");
     558        _tagNameMap.put(ShotInfo.TAG_SELF_TIMER_2, "Self Timer 2");
     559        _tagNameMap.put(ShotInfo.TAG_FLASH_OUTPUT, "Flash Output");
     560
     561        _tagNameMap.put(Panorama.TAG_PANORAMA_FRAME_NUMBER, "Panorama Frame Number");
     562        _tagNameMap.put(Panorama.TAG_PANORAMA_DIRECTION, "Panorama Direction");
     563
     564        _tagNameMap.put(AFInfo.TAG_NUM_AF_POINTS, "AF Point Count");
     565        _tagNameMap.put(AFInfo.TAG_VALID_AF_POINTS, "Valid AF Point Count");
     566        _tagNameMap.put(AFInfo.TAG_IMAGE_WIDTH, "Image Width");
     567        _tagNameMap.put(AFInfo.TAG_IMAGE_HEIGHT, "Image Height");
     568        _tagNameMap.put(AFInfo.TAG_AF_IMAGE_WIDTH, "AF Image Width");
     569        _tagNameMap.put(AFInfo.TAG_AF_IMAGE_HEIGHT, "AF Image Height");
     570        _tagNameMap.put(AFInfo.TAG_AF_AREA_WIDTH, "AF Area Width");
     571        _tagNameMap.put(AFInfo.TAG_AF_AREA_HEIGHT, "AF Area Height");
     572        _tagNameMap.put(AFInfo.TAG_AF_AREA_X_POSITIONS, "AF Area X Positions");
     573        _tagNameMap.put(AFInfo.TAG_AF_AREA_Y_POSITIONS, "AF Area Y Positions");
     574        _tagNameMap.put(AFInfo.TAG_AF_POINTS_IN_FOCUS, "AF Points in Focus Count");
     575        _tagNameMap.put(AFInfo.TAG_PRIMARY_AF_POINT_1, "Primary AF Point 1");
     576        _tagNameMap.put(AFInfo.TAG_PRIMARY_AF_POINT_2, "Primary AF Point 2");
     577       
     578//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION, "Long Exposure Noise Reduction");
     579//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS, "Shutter/Auto Exposure-lock Buttons");
     580//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP, "Mirror Lockup");
     581//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL, "Tv/Av And Exposure Level");
     582//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT, "AF-Assist Light");
     583//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE, "Shutter Speed in Av Mode");
     584//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_BRACKETTING, "Auto-Exposure Bracketting Sequence/Auto Cancellation");
     585//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC, "Shutter Curtain Sync");
     586//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_AF_STOP, "Lens Auto-Focus Stop Button Function Switch");
     587//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION, "Auto Reduction of Fill Flash");
     588//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN, "Menu Button Return Position");
     589//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION, "SET Button Function When Shooting");
     590//        _tagNameMap.put(TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING, "Sensor Cleaning");
     591
     592        _tagNameMap.put(TAG_THUMBNAIL_IMAGE_VALID_AREA, "Thumbnail Image Valid Area");
     593        _tagNameMap.put(TAG_SERIAL_NUMBER_FORMAT, "Serial Number Format");
     594        _tagNameMap.put(TAG_SUPER_MACRO, "Super Macro");
     595        _tagNameMap.put(TAG_DATE_STAMP_MODE, "Date Stamp Mode");
     596        _tagNameMap.put(TAG_MY_COLORS, "My Colors");
     597        _tagNameMap.put(TAG_FIRMWARE_REVISION, "Firmware Revision");
     598        _tagNameMap.put(TAG_CATEGORIES, "Categories");
     599        _tagNameMap.put(TAG_FACE_DETECT_ARRAY_1, "Face Detect Array 1");
     600        _tagNameMap.put(TAG_FACE_DETECT_ARRAY_2, "Face Detect Array 2");
     601        _tagNameMap.put(TAG_AF_INFO_ARRAY_2, "AF Info Array 2");
     602        _tagNameMap.put(TAG_IMAGE_UNIQUE_ID, "Image Unique ID");
     603        _tagNameMap.put(TAG_RAW_DATA_OFFSET, "Raw Data Offset");
     604        _tagNameMap.put(TAG_ORIGINAL_DECISION_DATA_OFFSET, "Original Decision Data Offset");
     605        _tagNameMap.put(TAG_CUSTOM_FUNCTIONS_1D_ARRAY, "Custom Functions (1D) Array");
     606        _tagNameMap.put(TAG_PERSONAL_FUNCTIONS_ARRAY, "Personal Functions Array");
     607        _tagNameMap.put(TAG_PERSONAL_FUNCTION_VALUES_ARRAY, "Personal Function Values Array");
     608        _tagNameMap.put(TAG_FILE_INFO_ARRAY, "File Info Array");
     609        _tagNameMap.put(TAG_AF_POINTS_IN_FOCUS_1D, "AF Points in Focus (1D)");
     610        _tagNameMap.put(TAG_LENS_MODEL, "Lens Model");
     611        _tagNameMap.put(TAG_SERIAL_INFO_ARRAY, "Serial Info Array");
     612        _tagNameMap.put(TAG_DUST_REMOVAL_DATA, "Dust Removal Data");
     613        _tagNameMap.put(TAG_CROP_INFO, "Crop Info");
     614        _tagNameMap.put(TAG_CUSTOM_FUNCTIONS_ARRAY_2, "Custom Functions Array 2");
     615        _tagNameMap.put(TAG_ASPECT_INFO_ARRAY, "Aspect Information Array");
     616        _tagNameMap.put(TAG_PROCESSING_INFO_ARRAY, "Processing Information Array");
     617        _tagNameMap.put(TAG_TONE_CURVE_TABLE, "Tone Curve Table");
     618        _tagNameMap.put(TAG_SHARPNESS_TABLE, "Sharpness Table");
     619        _tagNameMap.put(TAG_SHARPNESS_FREQ_TABLE, "Sharpness Frequency Table");
     620        _tagNameMap.put(TAG_WHITE_BALANCE_TABLE, "White Balance Table");
     621        _tagNameMap.put(TAG_COLOR_BALANCE_ARRAY, "Color Balance Array");
     622        _tagNameMap.put(TAG_MEASURED_COLOR_ARRAY, "Measured Color Array");
     623        _tagNameMap.put(TAG_COLOR_TEMPERATURE, "Color Temperature");
     624        _tagNameMap.put(TAG_CANON_FLAGS_ARRAY, "Canon Flags Array");
     625        _tagNameMap.put(TAG_MODIFIED_INFO_ARRAY, "Modified Information Array");
     626        _tagNameMap.put(TAG_TONE_CURVE_MATCHING, "Tone Curve Matching");
     627        _tagNameMap.put(TAG_WHITE_BALANCE_MATCHING, "White Balance Matching");
     628        _tagNameMap.put(TAG_COLOR_SPACE, "Color Space");
     629        _tagNameMap.put(TAG_PREVIEW_IMAGE_INFO_ARRAY, "Preview Image Info Array");
     630        _tagNameMap.put(TAG_VRD_OFFSET, "VRD Offset");
     631        _tagNameMap.put(TAG_SENSOR_INFO_ARRAY, "Sensor Information Array");
     632        _tagNameMap.put(TAG_COLOR_DATA_ARRAY_2, "Color Data Array 1");
     633        _tagNameMap.put(TAG_COLOR_INFO_ARRAY_2, "Color Data Array 2");
     634        _tagNameMap.put(TAG_CUSTOM_PICTURE_STYLE_FILE_NAME, "Custom Picture Style File Name");
     635        _tagNameMap.put(TAG_COLOR_INFO_ARRAY, "Color Info Array");
     636        _tagNameMap.put(TAG_VIGNETTING_CORRECTION_ARRAY_1, "Vignetting Correction Array 1");
     637        _tagNameMap.put(TAG_VIGNETTING_CORRECTION_ARRAY_2, "Vignetting Correction Array 2");
     638        _tagNameMap.put(TAG_LIGHTING_OPTIMIZER_ARRAY, "Lighting Optimizer Array");
     639        _tagNameMap.put(TAG_LENS_INFO_ARRAY, "Lens Info Array");
     640        _tagNameMap.put(TAG_AMBIANCE_INFO_ARRAY, "Ambiance Info Array");
     641        _tagNameMap.put(TAG_FILTER_INFO_ARRAY, "Filter Info Array");
    398642    }
    399643
     
    403647    }
    404648
     649    @NotNull
    405650    public String getName()
    406651    {
     
    408653    }
    409654
    410     protected HashMap getTagNameMap()
     655    @NotNull
     656    protected HashMap<Integer, String> getTagNameMap()
    411657    {
    412658        return _tagNameMap;
    413659    }
    414660
    415     /**
    416      * We need special handling for selected tags.
    417      * @param tagType
    418      * @param ints
    419      */
    420     public void setIntArray(int tagType, int[] ints)
    421     {
    422         if (tagType == TAG_CANON_CAMERA_STATE_1) {
    423             // this single tag has multiple values within
    424             int subTagTypeBase = 0xC100;
    425             // we intentionally skip the first array member
    426             for (int i = 1; i < ints.length; i++) {
    427                 setInt(subTagTypeBase + i, ints[i]);
    428             }
    429         } else if (tagType == TAG_CANON_CAMERA_STATE_2) {
    430             // this single tag has multiple values within
    431             int subTagTypeBase = 0xC200;
    432             // we intentionally skip the first array member
    433             for (int i = 1; i < ints.length; i++) {
    434                 setInt(subTagTypeBase + i, ints[i]);
    435             }
    436         } if (tagType == TAG_CANON_CUSTOM_FUNCTIONS) {
    437             // this single tag has multiple values within
    438             int subTagTypeBase = 0xC300;
    439             // we intentionally skip the first array member
    440             for (int i = 1; i < ints.length; i++) {
    441                 setInt(subTagTypeBase + i + 1, ints[i] & 0x0F);
    442             }
    443         } else {
    444             // no special handling...
    445             super.setIntArray(tagType, ints);
     661    @Override
     662    public void setIntArray(int tagType, @NotNull int[] ints)
     663    {
     664        // TODO is there some way to drop out 'null' or 'zero' values that are present in the array to reduce the noise?
     665       
     666        // Certain Canon tags contain arrays of values that we split into 'fake' tags as each
     667        // index in the array has its own meaning and decoding.
     668        // Pick those tags out here and throw away the original array.
     669        // Otherwise just add as usual.
     670        switch (tagType) {
     671            case TAG_CAMERA_SETTINGS_ARRAY:
     672                for (int i = 0; i < ints.length; i++)
     673                    setInt(CameraSettings.OFFSET + i, ints[i]);
     674                break;
     675            case TAG_FOCAL_LENGTH_ARRAY:
     676                for (int i = 0; i < ints.length; i++)
     677                    setInt(FocalLength.OFFSET + i, ints[i]);
     678                break;
     679            case TAG_SHOT_INFO_ARRAY:
     680                for (int i = 0; i < ints.length; i++)
     681                    setInt(ShotInfo.OFFSET + i, ints[i]);
     682                break;
     683            case TAG_PANORAMA_ARRAY:
     684                for (int i = 0; i < ints.length; i++)
     685                    setInt(Panorama.OFFSET + i, ints[i]);
     686                break;
     687            // TODO the interpretation of the custom functions tag depends upon the camera model
     688//            case TAG_CANON_CUSTOM_FUNCTIONS_ARRAY:
     689//                int subTagTypeBase = 0xC300;
     690//                // we intentionally skip the first array member
     691//                for (int i = 1; i < ints.length; i++)
     692//                    setInt(subTagTypeBase + i + 1, ints[i] & 0x0F);
     693//                break;
     694            case TAG_AF_INFO_ARRAY:
     695                for (int i = 0; i < ints.length; i++)
     696                    setInt(AFInfo.OFFSET + i, ints[i]);
     697                break;
     698            default:
     699                // no special handling...
     700                super.setIntArray(tagType, ints);
     701                break;
    446702        }
    447703    }
  • trunk/src/com/drew/metadata/exif/CasioType1MakernoteDescriptor.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
    6  *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
    9  *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
    14  *
    15  * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
     2 * Copyright 2002-2012 Drew Noakes
     3 *
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
     7 *
     8 *        http://www.apache.org/licenses/LICENSE-2.0
     9 *
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
    19 import com.drew.metadata.Directory;
    20 import com.drew.metadata.MetadataException;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
    2125import com.drew.metadata.TagDescriptor;
    2226
    2327/**
    24  *
     28 * Provides human-readable string representations of tag values stored in a <code>CasioType1MakernoteDirectory</code>.
     29 *
     30 * @author Drew Noakes http://drewnoakes.com
    2531 */
    26 public class CasioType1MakernoteDescriptor extends TagDescriptor
     32public class CasioType1MakernoteDescriptor extends TagDescriptor<CasioType1MakernoteDirectory>
    2733{
    28     public CasioType1MakernoteDescriptor(Directory directory)
     34    public CasioType1MakernoteDescriptor(@NotNull CasioType1MakernoteDirectory directory)
    2935    {
    3036        super(directory);
    3137    }
    3238
    33     public String getDescription(int tagType) throws MetadataException
     39    @Nullable
     40    public String getDescription(int tagType)
    3441    {
    3542        switch (tagType) {
     
    5966                return getCcdSensitivityDescription();
    6067            default:
    61                 return _directory.getString(tagType);
    62         }
    63     }
    64 
    65     public String getCcdSensitivityDescription() throws MetadataException
    66     {
    67         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY)) return null;
    68         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY);
     68                return super.getDescription(tagType);
     69        }
     70    }
     71
     72    @Nullable
     73    public String getCcdSensitivityDescription()
     74    {
     75        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY);
     76
     77        if (value == null)
     78            return null;
     79
    6980        switch (value) {
    7081            // these four for QV3000
     
    8798    }
    8899
    89     public String getSaturationDescription() throws MetadataException
    90     {
    91         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION)) return null;
    92         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION);
     100    @Nullable
     101    public String getSaturationDescription()
     102    {
     103        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION);
     104
     105        if (value == null)
     106            return null;
     107
    93108        switch (value) {
    94109            case 0:
     
    103118    }
    104119
    105     public String getContrastDescription() throws MetadataException
    106     {
    107         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST)) return null;
    108         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST);
     120    @Nullable
     121    public String getContrastDescription()
     122    {
     123        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST);
     124
     125        if (value == null)
     126            return null;
     127
    109128        switch (value) {
    110129            case 0:
     
    119138    }
    120139
    121     public String getSharpnessDescription() throws MetadataException
    122     {
    123         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS)) return null;
    124         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS);
     140    @Nullable
     141    public String getSharpnessDescription()
     142    {
     143        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS);
     144
     145        if (value == null)
     146            return null;
     147
    125148        switch (value) {
    126149            case 0:
     
    135158    }
    136159
    137     public String getDigitalZoomDescription() throws MetadataException
    138     {
    139         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM)) return null;
    140         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM);
     160    @Nullable
     161    public String getDigitalZoomDescription()
     162    {
     163        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM);
     164
     165        if (value == null)
     166            return null;
     167
    141168        switch (value) {
    142169            case 0x10000:
     
    153180    }
    154181
    155     public String getWhiteBalanceDescription() throws MetadataException
    156     {
    157         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE)) return null;
    158         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE);
     182    @Nullable
     183    public String getWhiteBalanceDescription()
     184    {
     185        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE);
     186
     187        if (value == null)
     188            return null;
     189
    159190        switch (value) {
    160191            case 1:
     
    165196                return "Daylight";
    166197            case 4:
    167                 return "Flourescent";
     198                return "Florescent";
    168199            case 5:
    169200                return "Shade";
     
    175206    }
    176207
    177     public String getObjectDistanceDescription() throws MetadataException
    178     {
    179         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE)) return null;
    180         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE);
     208    @Nullable
     209    public String getObjectDistanceDescription()
     210    {
     211        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE);
     212
     213        if (value == null)
     214            return null;
     215
    181216        return value + " mm";
    182217    }
    183218
    184     public String getFlashIntensityDescription() throws MetadataException
    185     {
    186         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY)) return null;
    187         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY);
     219    @Nullable
     220    public String getFlashIntensityDescription()
     221    {
     222        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY);
     223
     224        if (value == null)
     225            return null;
     226
    188227        switch (value) {
    189228            case 11:
     
    198237    }
    199238
    200     public String getFlashModeDescription() throws MetadataException
    201     {
    202         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE)) return null;
    203         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE);
     239    @Nullable
     240    public String getFlashModeDescription()
     241    {
     242        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE);
     243
     244        if (value == null)
     245            return null;
     246
    204247        switch (value) {
    205248            case 1:
     
    218261    }
    219262
    220     public String getFocusingModeDescription() throws MetadataException
    221     {
    222         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE)) return null;
    223         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE);
     263    @Nullable
     264    public String getFocusingModeDescription()
     265    {
     266        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE);
     267
     268        if (value == null)
     269            return null;
     270
    224271        switch (value) {
    225272            case 2:
     
    236283    }
    237284
    238     public String getQualityDescription() throws MetadataException
    239     {
    240         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY)) return null;
    241         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY);
     285    @Nullable
     286    public String getQualityDescription()
     287    {
     288        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY);
     289
     290        if (value == null)
     291            return null;
     292
    242293        switch (value) {
    243294            case 1:
     
    252303    }
    253304
    254     public String getRecordingModeDescription() throws MetadataException
    255     {
    256         if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE)) return null;
    257         int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE);
     305    @Nullable
     306    public String getRecordingModeDescription()
     307    {
     308        Integer value = _directory.getInteger(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE);
     309
     310        if (value == null)
     311            return null;
     312
    258313        switch (value) {
    259314            case 1:
  • trunk/src/com/drew/metadata/exif/CasioType1MakernoteDirectory.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
     23import com.drew.lang.annotations.NotNull;
    1924import com.drew.metadata.Directory;
    2025
     
    2227
    2328/**
     29 * Describes tags specific to Casio (type 1) cameras.
     30 *
    2431 * A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment.
    2532 * Makernote data begins immediately (no header).
     33 *
     34 * @author Drew Noakes http://drewnoakes.com
    2635 */
    2736public class CasioType1MakernoteDirectory extends Directory
     
    4857    public static final int TAG_CASIO_CCD_SENSITIVITY = 0x0014;
    4958
    50     protected static final HashMap<Integer, String> tagNameMap = new HashMap<Integer, String>();
     59    @NotNull
     60    protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
    5161
    5262    static
    5363    {
    54         tagNameMap.put(new Integer(TAG_CASIO_CCD_SENSITIVITY), "CCD Sensitivity");
    55         tagNameMap.put(new Integer(TAG_CASIO_CONTRAST), "Contrast");
    56         tagNameMap.put(new Integer(TAG_CASIO_DIGITAL_ZOOM), "Digital Zoom");
    57         tagNameMap.put(new Integer(TAG_CASIO_FLASH_INTENSITY), "Flash Intensity");
    58         tagNameMap.put(new Integer(TAG_CASIO_FLASH_MODE), "Flash Mode");
    59         tagNameMap.put(new Integer(TAG_CASIO_FOCUSING_MODE), "Focussing Mode");
    60         tagNameMap.put(new Integer(TAG_CASIO_OBJECT_DISTANCE), "Object Distance");
    61         tagNameMap.put(new Integer(TAG_CASIO_QUALITY), "Quality");
    62         tagNameMap.put(new Integer(TAG_CASIO_RECORDING_MODE), "Recording Mode");
    63         tagNameMap.put(new Integer(TAG_CASIO_SATURATION), "Saturation");
    64         tagNameMap.put(new Integer(TAG_CASIO_SHARPNESS), "Sharpness");
    65         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_1), "Makernote Unknown 1");
    66         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_2), "Makernote Unknown 2");
    67         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_3), "Makernote Unknown 3");
    68         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_4), "Makernote Unknown 4");
    69         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_5), "Makernote Unknown 5");
    70         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_6), "Makernote Unknown 6");
    71         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_7), "Makernote Unknown 7");
    72         tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_8), "Makernote Unknown 8");
    73         tagNameMap.put(new Integer(TAG_CASIO_WHITE_BALANCE), "White Balance");
     64        _tagNameMap.put(TAG_CASIO_CCD_SENSITIVITY, "CCD Sensitivity");
     65        _tagNameMap.put(TAG_CASIO_CONTRAST, "Contrast");
     66        _tagNameMap.put(TAG_CASIO_DIGITAL_ZOOM, "Digital Zoom");
     67        _tagNameMap.put(TAG_CASIO_FLASH_INTENSITY, "Flash Intensity");
     68        _tagNameMap.put(TAG_CASIO_FLASH_MODE, "Flash Mode");
     69        _tagNameMap.put(TAG_CASIO_FOCUSING_MODE, "Focusing Mode");
     70        _tagNameMap.put(TAG_CASIO_OBJECT_DISTANCE, "Object Distance");
     71        _tagNameMap.put(TAG_CASIO_QUALITY, "Quality");
     72        _tagNameMap.put(TAG_CASIO_RECORDING_MODE, "Recording Mode");
     73        _tagNameMap.put(TAG_CASIO_SATURATION, "Saturation");
     74        _tagNameMap.put(TAG_CASIO_SHARPNESS, "Sharpness");
     75        _tagNameMap.put(TAG_CASIO_UNKNOWN_1, "Makernote Unknown 1");
     76        _tagNameMap.put(TAG_CASIO_UNKNOWN_2, "Makernote Unknown 2");
     77        _tagNameMap.put(TAG_CASIO_UNKNOWN_3, "Makernote Unknown 3");
     78        _tagNameMap.put(TAG_CASIO_UNKNOWN_4, "Makernote Unknown 4");
     79        _tagNameMap.put(TAG_CASIO_UNKNOWN_5, "Makernote Unknown 5");
     80        _tagNameMap.put(TAG_CASIO_UNKNOWN_6, "Makernote Unknown 6");
     81        _tagNameMap.put(TAG_CASIO_UNKNOWN_7, "Makernote Unknown 7");
     82        _tagNameMap.put(TAG_CASIO_UNKNOWN_8, "Makernote Unknown 8");
     83        _tagNameMap.put(TAG_CASIO_WHITE_BALANCE, "White Balance");
    7484    }
    7585
     
    7989    }
    8090
     91    @NotNull
    8192    public String getName()
    8293    {
     
    8495    }
    8596
    86     protected HashMap getTagNameMap()
     97    @NotNull
     98    protected HashMap<Integer, String> getTagNameMap()
    8799    {
    88         return tagNameMap;
     100        return _tagNameMap;
    89101    }
    90102}
  • trunk/src/com/drew/metadata/exif/CasioType2MakernoteDescriptor.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
    6  *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
    9  *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
    14  *
    15  * Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
     2 * Copyright 2002-2012 Drew Noakes
     3 *
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
     7 *
     8 *        http://www.apache.org/licenses/LICENSE-2.0
     9 *
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
    19 import com.drew.metadata.Directory;
    20 import com.drew.metadata.MetadataException;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
    2125import com.drew.metadata.TagDescriptor;
    2226
    2327/**
    24  *
     28 * Provides human-readable string representations of tag values stored in a <code>CasioType2MakernoteDirectory</code>.
     29 *
     30 * @author Drew Noakes http://drewnoakes.com
    2531 */
    26 public class CasioType2MakernoteDescriptor extends TagDescriptor
     32public class CasioType2MakernoteDescriptor extends TagDescriptor<CasioType2MakernoteDirectory>
    2733{
    28     public CasioType2MakernoteDescriptor(Directory directory)
     34    public CasioType2MakernoteDescriptor(@NotNull CasioType2MakernoteDirectory directory)
    2935    {
    3036        super(directory);
    3137    }
    3238
    33     public String getDescription(int tagType) throws MetadataException
     39    @Nullable
     40    public String getDescription(int tagType)
    3441    {
    3542        switch (tagType) {
     
    9198                return getFilterDescription();
    9299            default:
    93                 return _directory.getString(tagType);
    94         }
    95     }
    96 
    97     public String getFilterDescription() throws MetadataException
    98     {
    99         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER)) return null;
    100         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER);
    101         switch (value) {
    102             case 0:
    103                 return "Off";
    104             default:
    105                 return "Unknown (" + value + ")";
    106         }
    107     }
    108 
    109     public String getEnhancementDescription() throws MetadataException
    110     {
    111         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT)) return null;
    112         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT);
    113         switch (value) {
    114             case 0:
    115                 return "Off";
    116             default:
    117                 return "Unknown (" + value + ")";
    118         }
    119     }
    120 
    121     public String getColourModeDescription() throws MetadataException
    122     {
    123         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE)) return null;
    124         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE);
    125         switch (value) {
    126             case 0:
    127                 return "Off";
    128             default:
    129                 return "Unknown (" + value + ")";
    130         }
    131     }
    132 
    133     public String getCcdIsoSensitivityDescription() throws MetadataException
    134     {
    135         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY)) return null;
    136         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY);
     100                return super.getDescription(tagType);
     101        }
     102    }
     103
     104    @Nullable
     105    public String getFilterDescription()
     106    {
     107        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER);
     108        if (value==null)
     109            return null;
     110        switch (value) {
     111            case 0:
     112                return "Off";
     113            default:
     114                return "Unknown (" + value + ")";
     115        }
     116    }
     117
     118    @Nullable
     119    public String getEnhancementDescription()
     120    {
     121        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT);
     122        if (value==null)
     123            return null;
     124        switch (value) {
     125            case 0:
     126                return "Off";
     127            default:
     128                return "Unknown (" + value + ")";
     129        }
     130    }
     131
     132    @Nullable
     133    public String getColourModeDescription()
     134    {
     135        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE);
     136        if (value==null)
     137            return null;
     138        switch (value) {
     139            case 0:
     140                return "Off";
     141            default:
     142                return "Unknown (" + value + ")";
     143        }
     144    }
     145
     146    @Nullable
     147    public String getCcdIsoSensitivityDescription()
     148    {
     149        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY);
     150        if (value==null)
     151            return null;
    137152        switch (value) {
    138153            case 0:
     
    145160    }
    146161
    147     public String getBestShotModeDescription() throws MetadataException
    148     {
    149         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE)) return null;
    150         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE);
    151         switch (value) {
    152             default:
    153                 return "Unknown (" + value + ")";
    154         }
    155     }
    156 
     162    @Nullable
     163    public String getBestShotModeDescription()
     164    {
     165        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE);
     166        if (value==null)
     167            return null;
     168        switch (value) {
     169            default:
     170                return "Unknown (" + value + ")";
     171        }
     172    }
     173
     174    @Nullable
    157175    public String getTimeZoneDescription()
    158176    {
    159         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE)) return null;
    160177        return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE);
    161178    }
    162179
    163     public String getFocusMode2Description() throws MetadataException
    164     {
    165         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2)) return null;
    166         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2);
     180    @Nullable
     181    public String getFocusMode2Description()
     182    {
     183        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2);
     184        if (value==null)
     185            return null;
    167186        switch (value) {
    168187            case 1:
     
    175194    }
    176195
    177     public String getQualityDescription() throws MetadataException
    178     {
    179         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY)) return null;
    180         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY);
     196    @Nullable
     197    public String getQualityDescription()
     198    {
     199        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY);
     200        if (value==null)
     201            return null;
    181202        switch (value) {
    182203            case 3:
     
    187208    }
    188209
    189     public String getSelfTimerDescription() throws MetadataException
    190     {
    191         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER)) return null;
    192         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER);
    193         switch (value) {
    194             case 1:
    195                 return "Off";
    196             default:
    197                 return "Unknown (" + value + ")";
    198         }
    199     }
    200 
    201     public String getRecordModeDescription() throws MetadataException
    202     {
    203         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE)) return null;
    204         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE);
     210    @Nullable
     211    public String getSelfTimerDescription()
     212    {
     213        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER);
     214        if (value==null)
     215            return null;
     216        switch (value) {
     217            case 1:
     218                return "Off";
     219            default:
     220                return "Unknown (" + value + ")";
     221        }
     222    }
     223
     224    @Nullable
     225    public String getRecordModeDescription()
     226    {
     227        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE);
     228        if (value==null)
     229            return null;
    205230        switch (value) {
    206231            case 2:
     
    211236    }
    212237
    213     public String getFlashDistanceDescription() throws MetadataException
    214     {
    215         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE)) return null;
    216         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE);
    217         switch (value) {
    218             case 0:
    219                 return "Off";
    220             default:
    221                 return "Unknown (" + value + ")";
    222         }
    223     }
    224 
    225     public String getObjectDistanceDescription() throws MetadataException
    226     {
    227         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE)) return null;
    228         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE);
     238    @Nullable
     239    public String getFlashDistanceDescription()
     240    {
     241        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE);
     242        if (value==null)
     243            return null;
     244        switch (value) {
     245            case 0:
     246                return "Off";
     247            default:
     248                return "Unknown (" + value + ")";
     249        }
     250    }
     251
     252    @Nullable
     253    public String getObjectDistanceDescription()
     254    {
     255        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE);
     256        if (value==null)
     257            return null;
    229258        return Integer.toString(value) + " mm";
    230259    }
    231260
    232     public String getWhiteBalance2Description() throws MetadataException
    233     {
    234         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2)) return null;
    235         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2);
     261    @Nullable
     262    public String getWhiteBalance2Description()
     263    {
     264        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2);
     265        if (value==null)
     266            return null;
    236267        switch (value) {
    237268            case 0:
     
    248279    }
    249280
     281    @Nullable
    250282    public String getWhiteBalanceBiasDescription()
    251283    {
    252         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS)) return null;
    253284        return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS);
    254285    }
    255286
    256     public String getCasioPreviewThumbnailDescription() throws MetadataException
    257     {
    258         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL)) return null;
     287    @Nullable
     288    public String getCasioPreviewThumbnailDescription()
     289    {
    259290        final byte[] bytes = _directory.getByteArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL);
     291        if (bytes==null)
     292            return null;
    260293        return "<" + bytes.length + " bytes of image data>";
    261294    }
    262295
     296    @Nullable
    263297    public String getPrintImageMatchingInfoDescription()
    264298    {
    265299        // TODO research PIM specification http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html
    266         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO)) return null;
    267300        return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO);
    268301    }
    269302
    270     public String getSharpnessDescription() throws MetadataException
    271     {
    272         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS)) return null;
    273         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS);
     303    @Nullable
     304    public String getSharpnessDescription()
     305    {
     306        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS);
     307        if (value==null)
     308            return null;
    274309        switch (value) {
    275310            case 0:
     
    284319    }
    285320
    286     public String getContrastDescription() throws MetadataException
    287     {
    288         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST)) return null;
    289         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST);
     321    @Nullable
     322    public String getContrastDescription()
     323    {
     324        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST);
     325        if (value==null)
     326            return null;
    290327        switch (value) {
    291328            case 0:
     
    300337    }
    301338
    302     public String getSaturationDescription() throws MetadataException
    303     {
    304         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION)) return null;
    305         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION);
     339    @Nullable
     340    public String getSaturationDescription()
     341    {
     342        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION);
     343        if (value==null)
     344            return null;
    306345        switch (value) {
    307346            case 0:
     
    316355    }
    317356
    318     public String getFocalLengthDescription() throws MetadataException
    319     {
    320         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH)) return null;
    321         double value = _directory.getDouble(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH);
     357    @Nullable
     358    public String getFocalLengthDescription()
     359    {
     360        Double value = _directory.getDoubleObject(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH);
     361        if (value==null)
     362            return null;
    322363        return Double.toString(value / 10d) + " mm";
    323364    }
    324365
    325     public String getWhiteBalance1Description() throws MetadataException
    326     {
    327         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1)) return null;
    328         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1);
     366    @Nullable
     367    public String getWhiteBalance1Description()
     368    {
     369        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1);
     370        if (value==null)
     371            return null;
    329372        switch (value) {
    330373            case 0:
     
    337380                return "Tungsten";
    338381            case 4:
    339                 return "Flourescent";
     382                return "Florescent";
    340383            case 5:
    341384                return "Manual";
     
    345388    }
    346389
    347     public String getIsoSensitivityDescription() throws MetadataException
    348     {
    349         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY)) return null;
    350         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY);
     390    @Nullable
     391    public String getIsoSensitivityDescription()
     392    {
     393        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY);
     394        if (value==null)
     395            return null;
    351396        switch (value) {
    352397            case 3:
     
    363408    }
    364409
    365     public String getFocusMode1Description() throws MetadataException
    366     {
    367         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1)) return null;
    368         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1);
     410    @Nullable
     411    public String getFocusMode1Description()
     412    {
     413        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1);
     414        if (value==null)
     415            return null;
    369416        switch (value) {
    370417            case 0:
     
    377424    }
    378425
    379     public String getImageSizeDescription() throws MetadataException
    380     {
    381         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE)) return null;
    382         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE);
     426    @Nullable
     427    public String getImageSizeDescription()
     428    {
     429        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE);
     430        if (value==null)
     431            return null;
    383432        switch (value) {
    384433            case 0:  return "640 x 480 pixels";
     
    393442    }
    394443
    395     public String getQualityModeDescription() throws MetadataException
    396     {
    397         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE)) return null;
    398         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE);
     444    @Nullable
     445    public String getQualityModeDescription()
     446    {
     447        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE);
     448        if (value==null)
     449            return null;
    399450        switch (value) {
    400451            case 1:
     
    407458    }
    408459
     460    @Nullable
    409461    public String getThumbnailOffsetDescription()
    410462    {
    411         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET)) return null;
    412463        return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET);
    413464    }
    414465
    415     public String getThumbnailSizeDescription() throws MetadataException
    416     {
    417         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE)) return null;
    418         int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE);
     466    @Nullable
     467    public String getThumbnailSizeDescription()
     468    {
     469        Integer value = _directory.getInteger(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE);
     470        if (value==null)
     471            return null;
    419472        return Integer.toString(value) + " bytes";
    420473    }
    421474
    422     public String getThumbnailDimensionsDescription() throws MetadataException
    423     {
    424         if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS)) return null;
     475    @Nullable
     476    public String getThumbnailDimensionsDescription()
     477    {
    425478        int[] dimensions = _directory.getIntArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS);
    426         if (dimensions.length!=2)
     479        if (dimensions==null || dimensions.length!=2)
    427480            return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS);
    428481        return dimensions[0] + " x " + dimensions[1] + " pixels";
  • trunk/src/com/drew/metadata/exif/CasioType2MakernoteDirectory.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
    6  *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
    9  *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
    14  *
    15  * Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
     2 * Copyright 2002-2012 Drew Noakes
     3 *
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
     7 *
     8 *        http://www.apache.org/licenses/LICENSE-2.0
     9 *
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
     23import com.drew.lang.annotations.NotNull;
    1924import com.drew.metadata.Directory;
    2025
     
    2227
    2328/**
     29 * Describes tags specific to Casio (type 2) cameras.
     30 *
    2431 * A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment.
    2532 * Makernote data begins after a 6-byte header: "QVC\x00\x00\x00"
     33 *
     34 * @author Drew Noakes http://drewnoakes.com
    2635 */
    2736public class CasioType2MakernoteDirectory extends Directory
     
    167176    public static final int TAG_CASIO_TYPE2_FILTER = 0x3017;
    168177
    169     protected static final HashMap tagNameMap = new HashMap();
     178    @NotNull
     179    protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
    170180
    171181    static
    172182    {
    173         // TODO add names
    174         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS), "Thumbnail Dimensions");
    175         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_SIZE), "Thumbnail Size");
    176         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_OFFSET), "Thumbnail Offset");
    177         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_QUALITY_MODE), "Quality Mode");
    178         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_IMAGE_SIZE), "Image Size");
    179         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_1), "Focus Mode");
    180         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_ISO_SENSITIVITY), "ISO Sensitivity");
    181         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_1), "White Balance");
    182         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCAL_LENGTH), "Focal Length");
    183         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SATURATION), "Saturation");
    184         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CONTRAST), "Contrast");
    185         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SHARPNESS), "Sharpness");
    186         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");
    187         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL), "Casio Preview Thumbnail");
    188         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS), "White Balance Bias");
    189         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_2), "White Balance");
    190         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_OBJECT_DISTANCE), "Object Distance");
    191         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FLASH_DISTANCE), "Flash Distance");
    192         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_RECORD_MODE), "Record Mode");
    193         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SELF_TIMER), "Self Timer");
    194         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_QUALITY), "Quality");
    195         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_2), "Focus Mode");
    196         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_TIME_ZONE), "Time Zone");
    197         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_BESTSHOT_MODE), "BestShot Mode");
    198         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY), "CCD ISO Sensitivity");
    199         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_COLOUR_MODE), "Colour Mode");
    200         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_ENHANCEMENT), "Enhancement");
    201         tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FILTER), "Filter");
     183        // TODO add missing names
     184        _tagNameMap.put(TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS, "Thumbnail Dimensions");
     185        _tagNameMap.put(TAG_CASIO_TYPE2_THUMBNAIL_SIZE, "Thumbnail Size");
     186        _tagNameMap.put(TAG_CASIO_TYPE2_THUMBNAIL_OFFSET, "Thumbnail Offset");
     187        _tagNameMap.put(TAG_CASIO_TYPE2_QUALITY_MODE, "Quality Mode");
     188        _tagNameMap.put(TAG_CASIO_TYPE2_IMAGE_SIZE, "Image Size");
     189        _tagNameMap.put(TAG_CASIO_TYPE2_FOCUS_MODE_1, "Focus Mode");
     190        _tagNameMap.put(TAG_CASIO_TYPE2_ISO_SENSITIVITY, "ISO Sensitivity");
     191        _tagNameMap.put(TAG_CASIO_TYPE2_WHITE_BALANCE_1, "White Balance");
     192        _tagNameMap.put(TAG_CASIO_TYPE2_FOCAL_LENGTH, "Focal Length");
     193        _tagNameMap.put(TAG_CASIO_TYPE2_SATURATION, "Saturation");
     194        _tagNameMap.put(TAG_CASIO_TYPE2_CONTRAST, "Contrast");
     195        _tagNameMap.put(TAG_CASIO_TYPE2_SHARPNESS, "Sharpness");
     196        _tagNameMap.put(TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO, "Print Image Matching (PIM) Info");
     197        _tagNameMap.put(TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL, "Casio Preview Thumbnail");
     198        _tagNameMap.put(TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS, "White Balance Bias");
     199        _tagNameMap.put(TAG_CASIO_TYPE2_WHITE_BALANCE_2, "White Balance");
     200        _tagNameMap.put(TAG_CASIO_TYPE2_OBJECT_DISTANCE, "Object Distance");
     201        _tagNameMap.put(TAG_CASIO_TYPE2_FLASH_DISTANCE, "Flash Distance");
     202        _tagNameMap.put(TAG_CASIO_TYPE2_RECORD_MODE, "Record Mode");
     203        _tagNameMap.put(TAG_CASIO_TYPE2_SELF_TIMER, "Self Timer");
     204        _tagNameMap.put(TAG_CASIO_TYPE2_QUALITY, "Quality");
     205        _tagNameMap.put(TAG_CASIO_TYPE2_FOCUS_MODE_2, "Focus Mode");
     206        _tagNameMap.put(TAG_CASIO_TYPE2_TIME_ZONE, "Time Zone");
     207        _tagNameMap.put(TAG_CASIO_TYPE2_BESTSHOT_MODE, "BestShot Mode");
     208        _tagNameMap.put(TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY, "CCD ISO Sensitivity");
     209        _tagNameMap.put(TAG_CASIO_TYPE2_COLOUR_MODE, "Colour Mode");
     210        _tagNameMap.put(TAG_CASIO_TYPE2_ENHANCEMENT, "Enhancement");
     211        _tagNameMap.put(TAG_CASIO_TYPE2_FILTER, "Filter");
    202212    }
    203213
     
    207217    }
    208218
     219    @NotNull
    209220    public String getName()
    210221    {
     
    212223    }
    213224
    214     protected HashMap getTagNameMap()
    215     {
    216         return tagNameMap;
     225    @NotNull
     226    protected HashMap<Integer, String> getTagNameMap()
     227    {
     228        return _tagNameMap;
    217229    }
    218230}
  • trunk/src/com/drew/metadata/exif/DataFormat.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
     9 *
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1420 */
    1521package com.drew.metadata.exif;
    1622
     23import com.drew.lang.annotations.NotNull;
    1724import com.drew.metadata.MetadataException;
    1825
    1926/**
    2027 * An enumeration of data formats used in the TIFF IFDs.
     28 *
     29 * @author Drew Noakes http://drewnoakes.com
    2130 */
    2231public class DataFormat
    2332{
    24     public static final DataFormat BYTE = new DataFormat("BYTE", 1);
    25     public static final DataFormat STRING = new DataFormat("STRING", 2);
    26     public static final DataFormat USHORT = new DataFormat("USHORT", 3);
    27     public static final DataFormat ULONG = new DataFormat("ULONG", 4);
    28     public static final DataFormat URATIONAL = new DataFormat("URATIONAL", 5);
    29     public static final DataFormat SBYTE = new DataFormat("SBYTE", 6);
    30     public static final DataFormat UNDEFINED = new DataFormat("UNDEFINED", 7);
    31     public static final DataFormat SSHORT = new DataFormat("SSHORT", 8);
    32     public static final DataFormat SLONG = new DataFormat("SLONG", 9);
    33     public static final DataFormat SRATIONAL = new DataFormat("SRATIONAL", 10);
    34     public static final DataFormat SINGLE = new DataFormat("SINGLE", 11);
    35     public static final DataFormat DOUBLE = new DataFormat("DOUBLE", 12);
     33    @NotNull public static final DataFormat BYTE = new DataFormat("BYTE", 1);
     34    @NotNull public static final DataFormat STRING = new DataFormat("STRING", 2);
     35    @NotNull public static final DataFormat USHORT = new DataFormat("USHORT", 3);
     36    @NotNull public static final DataFormat ULONG = new DataFormat("ULONG", 4);
     37    @NotNull public static final DataFormat URATIONAL = new DataFormat("URATIONAL", 5);
     38    @NotNull public static final DataFormat SBYTE = new DataFormat("SBYTE", 6);
     39    @NotNull public static final DataFormat UNDEFINED = new DataFormat("UNDEFINED", 7);
     40    @NotNull public static final DataFormat SSHORT = new DataFormat("SSHORT", 8);
     41    @NotNull public static final DataFormat SLONG = new DataFormat("SLONG", 9);
     42    @NotNull public static final DataFormat SRATIONAL = new DataFormat("SRATIONAL", 10);
     43    @NotNull public static final DataFormat SINGLE = new DataFormat("SINGLE", 11);
     44    @NotNull public static final DataFormat DOUBLE = new DataFormat("DOUBLE", 12);
    3645
    37     private final String myName;
    38     private final int value;
     46    @NotNull private final String _name;
     47    private final int _value;
    3948
     49    @NotNull
    4050    public static DataFormat fromValue(int value) throws MetadataException
    4151    {
     
    5969    }
    6070
    61     private DataFormat(String name, int value)
     71    private DataFormat(@NotNull String name, int value)
    6272    {
    63         myName = name;
    64         this.value = value;
     73        _name = name;
     74        _value = value;
    6575    }
    6676
    6777    public int getValue()
    6878    {
    69         return value;
     79        return _value;
    7080    }
    7181
     82    @NotNull
    7283    public String toString()
    7384    {
    74         return myName;
     85        return _name;
    7586    }
    7687}
  • trunk/src/com/drew/metadata/exif/ExifInteropDescriptor.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 12-Nov-2002 22:27:34 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
    19 import com.drew.metadata.Directory;
    20 import com.drew.metadata.MetadataException;
     23import com.drew.lang.annotations.NotNull;
     24import com.drew.lang.annotations.Nullable;
    2125import com.drew.metadata.TagDescriptor;
    2226
    2327/**
     28 * Provides human-readable string representations of tag values stored in a <code>ExifInteropDirectory</code>.
    2429 *
     30 * @author Drew Noakes http://drewnoakes.com
    2531 */
    26 public class ExifInteropDescriptor extends TagDescriptor
     32public class ExifInteropDescriptor extends TagDescriptor<ExifInteropDirectory>
    2733{
    28     public ExifInteropDescriptor(Directory directory)
     34    public ExifInteropDescriptor(@NotNull ExifInteropDirectory directory)
    2935    {
    3036        super(directory);
    3137    }
    3238
    33     public String getDescription(int tagType) throws MetadataException
     39    @Nullable
     40    public String getDescription(int tagType)
    3441    {
    3542        switch (tagType) {
     
    3946                return getInteropVersionDescription();
    4047            default:
    41                 return _directory.getString(tagType);
     48                return super.getDescription(tagType);
    4249        }
    4350    }
    4451
    45     public String getInteropVersionDescription() throws MetadataException
     52    @Nullable
     53    public String getInteropVersionDescription()
    4654    {
    47         if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_VERSION)) return null;
    4855        int[] ints = _directory.getIntArray(ExifInteropDirectory.TAG_INTEROP_VERSION);
    49         return ExifDescriptor.convertBytesToVersionString(ints);
     56        return convertBytesToVersionString(ints, 2);
    5057    }
    5158
     59    @Nullable
    5260    public String getInteropIndexDescription()
    5361    {
    54         if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_INDEX)) return null;
    55         String interopIndex = _directory.getString(ExifInteropDirectory.TAG_INTEROP_INDEX).trim();
    56         if ("R98".equalsIgnoreCase(interopIndex)) {
    57             return "Recommended Exif Interoperability Rules (ExifR98)";
    58         } else {
    59             return "Unknown (" + interopIndex + ")";
    60         }
     62        String value = _directory.getString(ExifInteropDirectory.TAG_INTEROP_INDEX);
     63
     64        if (value==null)
     65            return null;
     66
     67        return "R98".equalsIgnoreCase(value.trim())
     68                ? "Recommended Exif Interoperability Rules (ExifR98)"
     69                : "Unknown (" + value + ")";
    6170    }
    6271}
  • trunk/src/com/drew/metadata/exif/ExifInteropDirectory.java

    r4231 r6127  
    11/*
    2  * This is public domain software - that is, you can do whatever you want
    3  * with it, and include it software that is licensed under the GNU or the
    4  * BSD license, or whatever other licence you choose, including proprietary
    5  * closed source licenses.  I do ask that you leave this header in tact.
     2 * Copyright 2002-2012 Drew Noakes
    63 *
    7  * If you make modifications to this code that you think would benefit the
    8  * wider community, please send me a copy and I'll post it on my site.
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    97 *
    10  * If you make use of this code, I'd appreciate hearing about it.
    11  *   drew@drewnoakes.com
    12  * Latest version of this software kept at
    13  *   http://drewnoakes.com/
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    149 *
    15  * Created by dnoakes on 26-Nov-2002 10:58:13 using IntelliJ IDEA.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
     15 *
     16 * More information about this project is available at:
     17 *
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    1620 */
    1721package com.drew.metadata.exif;
    1822
     23import com.drew.lang.annotations.NotNull;
    1924import com.drew.metadata.Directory;
    2025
     
    2227
    2328/**
     29 * Describes Exif interoperability tags.
    2430 *
     31 * @author Drew Noakes http://drewnoakes.com
    2532 */
    2633public class ExifInteropDirectory extends Directory
     
    3239    public static final int TAG_RELATED_IMAGE_LENGTH = 0x1002;
    3340
    34     protected static final HashMap tagNameMap;
     41    @NotNull
     42    protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
    3543
    3644    static
    3745    {
    38         tagNameMap = new HashMap();
    39         tagNameMap.put(new Integer(TAG_INTEROP_INDEX), "Interoperability Index");
    40         tagNameMap.put(new Integer(TAG_INTEROP_VERSION), "Interoperability Version");
    41         tagNameMap.put(new Integer(TAG_RELATED_IMAGE_FILE_FORMAT), "Related Image File Format");
    42         tagNameMap.put(new Integer(TAG_RELATED_IMAGE_WIDTH), "Related Image Width");
    43         tagNameMap.put(new Integer(TAG_RELATED_IMAGE_LENGTH), "Related Image Length");
     46        _tagNameMap.put(TAG_INTEROP_INDEX, "Interoperability Index");
     47        _tagNameMap.put(TAG_INTEROP_VERSION, "Interoperability Version");
     48        _tagNameMap.put(TAG_RELATED_IMAGE_FILE_FORMAT, "Related Image File Format");
     49        _tagNameMap.put(TAG_RELATED_IMAGE_WIDTH, "Related Image Width");
     50        _tagNameMap.put(TAG_RELATED_IMAGE_LENGTH, "Related Image Length");
    4451    }
    4552
     
    4956    }
    5057
     58    @NotNull
    5159    public String getName()
    5260    {
     
    5462    }
    5563
    56     protected HashMap getTagNameMap()
     64    @NotNull
     65    protected HashMap<Integer, String> getTagNameMap()
    5766    {
    58         return tagNameMap;
     67        return _tagNameMap;
    5968    }
    6069}
  • trunk/src/com/drew/metadata/exif/ExifReader.java

    r4231 r6127  
    11/*
    2  * EXIFExtractor.java
     2 * Copyright 2002-2012 Drew Noakes
    33 *
    4  * This class based upon code from Jhead, a C program for extracting and
    5  * manipulating the Exif data within files written by Matthias Wandel.
    6  *   http://www.sentex.net/~mwandel/jhead/
     4 *    Licensed under the Apache License, Version 2.0 (the "License");
     5 *    you may not use this file except in compliance with the License.
     6 *    You may obtain a copy of the License at
    77 *
    8  * Jhead is public domain software - that is, you can do whatever you want
    9  * with it, and include it software that is licensed under the GNU or the
    10  * BSD license, or whatever other licence you choose, including proprietary
    11  * closed source licenses.  Similarly, I release this Java version under the
    12  * same license, though I do ask that you leave this header in tact.
     8 *        http://www.apache.org/licenses/LICENSE-2.0
    139 *
    14  * If you make modifications to this code that you think would benefit the
    15  * wider community, please send me a copy and I'll post it on my site.  Unlike
    16  * Jhead, this code (as it stands) only supports reading of Exif data - no
    17  * manipulation, and no thumbnail stuff.
     10 *    Unless required by applicable law or agreed to in writing, software
     11 *    distributed under the License is distributed on an "AS IS" BASIS,
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 *    See the License for the specific language governing permissions and
     14 *    limitations under the License.
    1815 *
    19  * If you make use of this code, I'd appreciate hearing about it.
    20  *   drew.noakes@drewnoakes.com
    21  * Latest version of this software kept at
    22  *   http://drewnoakes.com/
     16 * More information about this project is available at:
    2317 *
    24  * Created on 28 April 2002, 23:54
    25  * Modified 04 Aug 2002
    26  * - Renamed constants to be inline with changes to ExifTagValues interface
    27  * - Substituted usage of JDK 1.4 features (java.nio package)
    28  * Modified 29 Oct 2002 (v1.2)
    29  * - Proper traversing of Exif file structure and complete refactor & tidy of
    30  *   the codebase (a few unnoticed bugs removed)
    31  * - Reads makernote data for 6 families of camera (5 makes)
    32  * - Tags now stored in directories... use the IFD_* constants to refer to the
    33  *   image file directory you require (Exif, Interop, GPS and Makernote*) --
    34  *   this avoids collisions where two tags share the same code
    35  * - Takes componentCount of unknown tags into account
    36  * - Now understands GPS tags (thanks to Colin Briton for his help with this)
    37  * - Some other bug fixes, pointed out by users around the world.  Thanks!
    38  * Modified 27 Nov 2002 (v2.0)
    39  * - Renamed to ExifReader
    40  * - Moved to new package com.drew.metadata.exif
    41  * Modified since, however changes have not been logged.  See release notes for
    42  * library-wide modifications.
     18 *    http://drewnoakes.com/code/exif/
     19 *    http://code.google.com/p/metadata-extractor/
    4320 */
    4421package com.drew.metadata.exif;
    4522
    46 import com.drew.imaging.jpeg.JpegProcessingException;
    47 import com.drew.imaging.jpeg.JpegSegmentData;
    48 import com.drew.imaging.jpeg.JpegSegmentReader;
     23import com.drew.lang.BufferBoundsException;
     24import com.drew.lang.BufferReader;
    4925import com.drew.lang.Rational;
     26import com.drew.lang.annotations.NotNull;
    5027import com.drew.metadata.Directory;
    5128import com.drew.metadata.Metadata;
    5229import com.drew.metadata.MetadataReader;
    5330
    54 import java.io.File;
    55 import java.io.InputStream;
    56 import java.util.HashMap;
     31import java.util.HashSet;
     32import java.util.Set;
    5733
    5834/**
    59  * Extracts Exif data from a JPEG header segment, providing information about the
    60  * camera/scanner/capture device (if available).  Information is encapsulated in
    61  * an <code>Metadata</code> object.
    62  * @author  Drew Noakes http://drewnoakes.com
     35 * Decodes Exif binary data, populating a {@link Metadata} object with tag values in {@link ExifSubIFDDirectory},