Index: trunk/src/com/drew/metadata/jpeg/JpegCommentDescriptor.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegCommentDescriptor.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegCommentDescriptor.java	(revision 6127)
@@ -1,37 +1,44 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
- * Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA.
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
-import com.drew.metadata.Directory;
+import com.drew.lang.annotations.NotNull;
+import com.drew.lang.annotations.Nullable;
 import com.drew.metadata.TagDescriptor;
 
 /**
+ * Provides human-readable string representations of tag values stored in a <code>JpegCommentDirectory</code>.
  *
  * @author Drew Noakes http://drewnoakes.com
  */
-public class JpegCommentDescriptor extends TagDescriptor
+public class JpegCommentDescriptor extends TagDescriptor<JpegCommentDirectory>
 {
-    public JpegCommentDescriptor(Directory directory)
+    public JpegCommentDescriptor(@NotNull JpegCommentDirectory directory)
     {
         super(directory);
     }
 
-    public String getDescription(int tagType)
+    @Nullable
+    public String getJpegCommentDescription()
     {
-        return _directory.getString(tagType);
+        return _directory.getString(JpegCommentDirectory.TAG_JPEG_COMMENT);
     }
 }
Index: trunk/src/com/drew/metadata/jpeg/JpegCommentDirectory.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegCommentDirectory.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegCommentDirectory.java	(revision 6127)
@@ -1,20 +1,25 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
- * Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA.
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
+import com.drew.lang.annotations.NotNull;
 import com.drew.metadata.Directory;
 
@@ -22,28 +27,38 @@
 
 /**
+ * Describes tags used by a JPEG file comment.
  *
  * @author Drew Noakes http://drewnoakes.com
  */
-public class JpegCommentDirectory extends Directory {
+public class JpegCommentDirectory extends Directory
+{
+    /**
+     * This value does not apply to a particular standard. Rather, this value has been fabricated to maintain
+     * consistency with other directory types.
+     */
+    public static final int TAG_JPEG_COMMENT = 0;
 
-	/** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */
-	public static final int TAG_JPEG_COMMENT = 0;
+    @NotNull
+    protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
 
-	protected static final HashMap tagNameMap = new HashMap();
+    static {
+        _tagNameMap.put(TAG_JPEG_COMMENT, "Jpeg Comment");
+    }
 
-	static {
-        tagNameMap.put(new Integer(TAG_JPEG_COMMENT), "Jpeg Comment");
-	}
+    public JpegCommentDirectory()
+    {
+        this.setDescriptor(new JpegCommentDescriptor(this));
+    }
 
-    public JpegCommentDirectory() {
-		this.setDescriptor(new JpegCommentDescriptor(this));
-	}
+    @NotNull
+    public String getName()
+    {
+        return "JpegComment";
+    }
 
-	public String getName() {
-		return "JpegComment";
-	}
-
-	protected HashMap getTagNameMap() {
-		return tagNameMap;
-	}
+    @NotNull
+    protected HashMap<Integer, String> getTagNameMap()
+    {
+        return _tagNameMap;
+    }
 }
Index: trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java	(revision 6127)
@@ -1,29 +1,33 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
- * Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA.
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
-import com.drew.imaging.jpeg.JpegProcessingException;
-import com.drew.imaging.jpeg.JpegSegmentReader;
+import com.drew.lang.BufferBoundsException;
+import com.drew.lang.BufferReader;
+import com.drew.lang.annotations.NotNull;
 import com.drew.metadata.Metadata;
 import com.drew.metadata.MetadataReader;
 
-import java.io.File;
-import java.io.InputStream;
-
 /**
+ * Decodes the comment stored within Jpeg files, populating a <code>Metadata</code> object with tag values in a
+ * <code>JpegCommentDirectory</code>.
  *
  * @author Drew Noakes http://drewnoakes.com
@@ -32,53 +36,16 @@
 {
     /**
-     * The COM data segment.
-     */
-    private final byte[] _data;
-
-    /**
-     * Creates a new JpegReader for the specified Jpeg jpegFile.
-     */
-    public JpegCommentReader(File jpegFile) throws JpegProcessingException
-    {
-        this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_COM));
-    }
-
-    /** Creates a JpegCommentReader for a JPEG stream.
-     *
-     * @param is JPEG stream. Stream will be closed.
-     */
-    public JpegCommentReader(InputStream is) throws JpegProcessingException
-    {
-        this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));
-    }
-
-    public JpegCommentReader(byte[] data)
-    {
-        _data = data;
-    }
-
-    /**
-     * Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>.
-     */
-    public Metadata extract()
-    {
-        return extract(new Metadata());
-    }
-
-    /**
      * Performs the Jpeg data extraction, adding found values to the specified
      * instance of <code>Metadata</code>.
      */
-    public Metadata extract(Metadata metadata)
+    public void extract(@NotNull final BufferReader reader, @NotNull Metadata metadata)
     {
-        if (_data==null) {
-            return metadata;
+        JpegCommentDirectory directory = metadata.getOrCreateDirectory(JpegCommentDirectory.class);
+
+        try {
+            directory.setString(JpegCommentDirectory.TAG_JPEG_COMMENT, reader.getString(0, (int)reader.getLength()));
+        } catch (BufferBoundsException e) {
+            directory.addError("Exception reading JPEG comment string");
         }
-
-        JpegCommentDirectory directory = (JpegCommentDirectory)metadata.getDirectory(JpegCommentDirectory.class);
-
-        directory.setString(JpegCommentDirectory.TAG_JPEG_COMMENT, new String(_data));
-
-        return metadata;
     }
 }
Index: trunk/src/com/drew/metadata/jpeg/JpegComponent.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegComponent.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegComponent.java	(revision 6127)
@@ -1,33 +1,38 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
- * Created by dnoakes on Oct 9, 17:04:07 using IntelliJ IDEA.
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
-import com.drew.metadata.MetadataException;
+import com.drew.lang.annotations.Nullable;
 
 import java.io.Serializable;
 
 /**
- * Created by IntelliJ IDEA.
- * User: dnoakes
- * Date: 09-Oct-2003
- * Time: 17:04:07
- * To change this template use Options | File Templates.
+ * Stores information about a Jpeg image component such as the component id, horiz/vert sampling factor and
+ * quantization table number.
+ *
+ * @author Drew Noakes http://drewnoakes.com
  */
 public class JpegComponent implements Serializable
 {
+    private static final long serialVersionUID = 61121257899091914L;
+
     private final int _componentId;
     private final int _samplingFactorByte;
@@ -46,5 +51,10 @@
     }
 
-    public String getComponentName() throws MetadataException
+    /**
+     * Returns the component name (one of: Y, Cb, Cr, I, or Q)
+     * @return the component name
+     */
+    @Nullable
+    public String getComponentName()
     {
         switch (_componentId)
@@ -61,6 +71,5 @@
                 return "Q";
         }
-
-        throw new MetadataException("Unsupported component id: " + _componentId);
+        return null;
     }
 
Index: trunk/src/com/drew/metadata/jpeg/JpegDescriptor.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegDescriptor.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegDescriptor.java	(revision 6127)
@@ -1,20 +1,26 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
-import com.drew.metadata.Directory;
-import com.drew.metadata.MetadataException;
+import com.drew.lang.annotations.NotNull;
+import com.drew.lang.annotations.Nullable;
 import com.drew.metadata.TagDescriptor;
 
@@ -22,16 +28,21 @@
  * Provides human-readable string versions of the tags stored in a JpegDirectory.
  * Thanks to Darrell Silver (www.darrellsilver.com) for the initial version of this class.
+ *
+ * @author Drew Noakes http://drewnoakes.com
  */
-public class JpegDescriptor extends TagDescriptor
+public class JpegDescriptor extends TagDescriptor<JpegDirectory>
 {
-    public JpegDescriptor(Directory directory)
+    public JpegDescriptor(@NotNull JpegDirectory directory)
     {
         super(directory);
     }
 
-    public String getDescription(int tagType) throws MetadataException
+    @Nullable
+    public String getDescription(int tagType)
     {
         switch (tagType)
         {
+            case JpegDirectory.TAG_JPEG_COMPRESSION_TYPE:
+                return getImageCompressionTypeDescription();
             case JpegDirectory.TAG_JPEG_COMPONENT_DATA_1:
                 return getComponentDataDescription(0);
@@ -48,39 +59,78 @@
             case JpegDirectory.TAG_JPEG_IMAGE_WIDTH:
                 return getImageWidthDescription();
+            default:
+                return super.getDescription(tagType);
         }
-
-        return _directory.getString(tagType);
     }
 
+    @Nullable
+    public String getImageCompressionTypeDescription()
+    {
+        Integer value = _directory.getInteger(JpegDirectory.TAG_JPEG_COMPRESSION_TYPE);
+        if (value==null)
+            return null;
+        // Note there is no 2 or 12
+        switch (value) {
+            case 0: return "Baseline";
+            case 1: return "Extended sequential, Huffman";
+            case 2: return "Progressive, Huffman";
+            case 3: return "Lossless, Huffman";
+            case 5: return "Differential sequential, Huffman";
+            case 6: return "Differential progressive, Huffman";
+            case 7: return "Differential lossless, Huffman";
+            case 8: return "Reserved for JPEG extensions";
+            case 9: return "Extended sequential, arithmetic";
+            case 10: return "Progressive, arithmetic";
+            case 11: return "Lossless, arithmetic";
+            case 13: return "Differential sequential, arithmetic";
+            case 14: return "Differential progressive, arithmetic";
+            case 15: return "Differential lossless, arithmetic";
+            default:
+                return "Unknown type: "+ value;
+        }
+    }
+    @Nullable
     public String getImageWidthDescription()
     {
-        return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_WIDTH) + " pixels";
+        final String value = _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
+        if (value==null)
+            return null;
+        return value + " pixels";
     }
 
+    @Nullable
     public String getImageHeightDescription()
     {
-        return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT) + " pixels";
+        final String value = _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
+        if (value==null)
+            return null;
+        return value + " pixels";
     }
 
+    @Nullable
     public String getDataPrecisionDescription()
     {
-        return _directory.getString(JpegDirectory.TAG_JPEG_DATA_PRECISION) + " bits";
+        final String value = _directory.getString(JpegDirectory.TAG_JPEG_DATA_PRECISION);
+        if (value==null)
+            return null;
+        return value + " bits";
     }
 
-    public String getComponentDataDescription(int componentNumber) throws MetadataException
+    @Nullable
+    public String getComponentDataDescription(int componentNumber)
     {
-        JpegComponent component = ((JpegDirectory)_directory).getComponent(componentNumber);
+        JpegComponent value = _directory.getComponent(componentNumber);
 
-        if (component==null)
-            throw new MetadataException("No Jpeg component exists with number " + componentNumber);
+        if (value==null)
+            return null;
 
-        StringBuffer sb = new StringBuffer();
-        sb.append(component.getComponentName());
+        StringBuilder sb = new StringBuilder();
+        sb.append(value.getComponentName());
         sb.append(" component: Quantization table ");
-        sb.append(component.getQuantizationTableNumber());
+        sb.append(value.getQuantizationTableNumber());
         sb.append(", Sampling factors ");
-        sb.append(component.getHorizontalSamplingFactor());
+        sb.append(value.getHorizontalSamplingFactor());
         sb.append(" horiz/");
-        sb.append(component.getVerticalSamplingFactor());
+        sb.append(value.getVerticalSamplingFactor());
         sb.append(" vert");
         return sb.toString();
Index: trunk/src/com/drew/metadata/jpeg/JpegDirectory.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegDirectory.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegDirectory.java	(revision 6127)
@@ -1,20 +1,26 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
- * Created on Aug 2, 2003.
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
+import com.drew.lang.annotations.NotNull;
+import com.drew.lang.annotations.Nullable;
 import com.drew.metadata.Directory;
 import com.drew.metadata.MetadataException;
@@ -24,73 +30,80 @@
 /**
  * Directory of tags and values for the SOF0 Jpeg segment.  This segment holds basic metadata about the image.
- * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes
+ *
+ * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes http://drewnoakes.com
  */
-public class JpegDirectory extends Directory {
-
-	/** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */
-	public static final int TAG_JPEG_DATA_PRECISION = 0;
-	/** The image's height.  Necessary for decoding the image, so it should always be there. */
-	public static final int TAG_JPEG_IMAGE_HEIGHT = 1;
-	/** The image's width.  Necessary for decoding the image, so it should always be there. */
-	public static final int TAG_JPEG_IMAGE_WIDTH = 3;
-	/** Usually 1 = grey scaled, 3 = color YcbCr or YIQ, 4 = color CMYK
-	 * Each component TAG_COMPONENT_DATA_[1-4], has the following meaning:
-	 * component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q),
-	 * sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.),
-	 * quantization table number (1 byte).
-	 * <p>
-	 * This info is from http://www.funducode.com/freec/Fileformats/format3/format3b.htm
-	 */
-	public static final int TAG_JPEG_NUMBER_OF_COMPONENTS = 5;
+public class JpegDirectory extends Directory
+{
+    public static final int TAG_JPEG_COMPRESSION_TYPE = -3;
+    /** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */
+    public static final int TAG_JPEG_DATA_PRECISION = 0;
+    /** The image's height.  Necessary for decoding the image, so it should always be there. */
+    public static final int TAG_JPEG_IMAGE_HEIGHT = 1;
+    /** The image's width.  Necessary for decoding the image, so it should always be there. */
+    public static final int TAG_JPEG_IMAGE_WIDTH = 3;
+    /**
+     * Usually 1 = grey scaled, 3 = color YcbCr or YIQ, 4 = color CMYK
+     * Each component TAG_COMPONENT_DATA_[1-4], has the following meaning:
+     * component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q),
+     * sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.),
+     * quantization table number (1 byte).
+     * <p/>
+     * This info is from http://www.funducode.com/freec/Fileformats/format3/format3b.htm
+     */
+    public static final int TAG_JPEG_NUMBER_OF_COMPONENTS = 5;
 
     // NOTE!  Component tag type int values must increment in steps of 1
 
-	/** the first of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
-	public static final int TAG_JPEG_COMPONENT_DATA_1 = 6;
-	/** the second of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
-	public static final int TAG_JPEG_COMPONENT_DATA_2 = 7;
-	/** the third of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
-	public static final int TAG_JPEG_COMPONENT_DATA_3 = 8;
-	/** the fourth of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
-	public static final int TAG_JPEG_COMPONENT_DATA_4 = 9;
+    /** the first of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */
+    public static final int TAG_JPEG_COMPONENT_DATA_1 = 6;
+    /** the second of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */
+    public static final int TAG_JPEG_COMPONENT_DATA_2 = 7;
+    /** the third of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */
+    public static final int TAG_JPEG_COMPONENT_DATA_3 = 8;
+    /** the fourth of a possible 4 color components.  Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS. */
+    public static final int TAG_JPEG_COMPONENT_DATA_4 = 9;
 
-	protected static final HashMap tagNameMap = new HashMap();
+    @NotNull
+    protected static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
 
-	static {
-        tagNameMap.put(new Integer(TAG_JPEG_DATA_PRECISION), "Data Precision");
-        tagNameMap.put(new Integer(TAG_JPEG_IMAGE_WIDTH), "Image Width");
-        tagNameMap.put(new Integer(TAG_JPEG_IMAGE_HEIGHT), "Image Height");
-		tagNameMap.put(new Integer(TAG_JPEG_NUMBER_OF_COMPONENTS), "Number of Components");
-		tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_1), "Component 1");
-		tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_2), "Component 2");
-		tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_3), "Component 3");
-		tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_4), "Component 4");
-	}
+    static {
+        _tagNameMap.put(TAG_JPEG_COMPRESSION_TYPE, "Compression Type");
+        _tagNameMap.put(TAG_JPEG_DATA_PRECISION, "Data Precision");
+        _tagNameMap.put(TAG_JPEG_IMAGE_WIDTH, "Image Width");
+        _tagNameMap.put(TAG_JPEG_IMAGE_HEIGHT, "Image Height");
+        _tagNameMap.put(TAG_JPEG_NUMBER_OF_COMPONENTS, "Number of Components");
+        _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_1, "Component 1");
+        _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_2, "Component 2");
+        _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_3, "Component 3");
+        _tagNameMap.put(TAG_JPEG_COMPONENT_DATA_4, "Component 4");
+    }
 
-    public JpegDirectory() {
-		this.setDescriptor(new JpegDescriptor(this));
-	}
+    public JpegDirectory()
+    {
+        this.setDescriptor(new JpegDescriptor(this));
+    }
 
-	public String getName() {
-		return "Jpeg";
-	}
+    @NotNull
+    public String getName()
+    {
+        return "Jpeg";
+    }
 
-	protected HashMap getTagNameMap() {
-		return tagNameMap;
-	}
+    @NotNull
+    protected HashMap<Integer, String> getTagNameMap()
+    {
+        return _tagNameMap;
+    }
 
     /**
-     *
      * @param componentNumber The zero-based index of the component.  This number is normally between 0 and 3.
-     *        Use getNumberOfComponents for bounds-checking.
-     * @return
+     *                        Use getNumberOfComponents for bounds-checking.
+     * @return the JpegComponent having the specified number.
      */
+    @Nullable
     public JpegComponent getComponent(int componentNumber)
     {
         int tagType = JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + componentNumber;
-
-        JpegComponent component = (JpegComponent)getObject(tagType);
-
-        return component;
+        return (JpegComponent)getObject(tagType);
     }
 
Index: trunk/src/com/drew/metadata/jpeg/JpegReader.java
===================================================================
--- trunk/src/com/drew/metadata/jpeg/JpegReader.java	(revision 4231)
+++ trunk/src/com/drew/metadata/jpeg/JpegReader.java	(revision 6127)
@@ -1,97 +1,60 @@
 /*
- * This is public domain software - that is, you can do whatever you want
- * with it, and include it software that is licensed under the GNU or the
- * BSD license, or whatever other licence you choose, including proprietary
- * closed source licenses.  I do ask that you leave this header in tact.
+ * Copyright 2002-2012 Drew Noakes
  *
- * If you make modifications to this code that you think would benefit the
- * wider community, please send me a copy and I'll post it on my site.
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
  *
- * If you make use of this code, I'd appreciate hearing about it.
- *   drew@drewnoakes.com
- * Latest version of this software kept at
- *   http://drewnoakes.com/
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
- * Created by dnoakes on Aug 2, 2003 using IntelliJ IDEA.
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ *
+ * More information about this project is available at:
+ *
+ *    http://drewnoakes.com/code/exif/
+ *    http://code.google.com/p/metadata-extractor/
  */
 package com.drew.metadata.jpeg;
 
-import com.drew.imaging.jpeg.JpegProcessingException;
-import com.drew.imaging.jpeg.JpegSegmentReader;
+import com.drew.lang.BufferBoundsException;
+import com.drew.lang.BufferReader;
+import com.drew.lang.annotations.NotNull;
 import com.drew.metadata.Metadata;
-import com.drew.metadata.MetadataException;
 import com.drew.metadata.MetadataReader;
 
-import java.io.File;
-import java.io.InputStream;
-
 /**
+ * Decodes Jpeg SOF0 data, populating a <code>Metadata</code> object with tag values in a <code>JpegDirectory</code>.
  *
- * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes
+ * @author Darrell Silver http://www.darrellsilver.com and Drew Noakes http://drewnoakes.com
  */
 public class JpegReader implements MetadataReader
 {
     /**
-     * The SOF0 data segment.
-     */
-    private final byte[] _data;
-
-    /**
-     * Creates a new JpegReader for the specified Jpeg jpegFile.
-     */
-    public JpegReader(File jpegFile) throws JpegProcessingException
-    {
-        this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_SOF0));
-    }
-
-    /** Creates a JpegReader for a JPEG stream.
-     *
-     * @param is JPEG stream. Stream will be closed.
-     */
-    public JpegReader(InputStream is) throws JpegProcessingException
-    {
-        this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));
-    }
-
-    public JpegReader(byte[] data)
-    {
-        _data = data;
-    }
-
-    /**
-     * Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>.
-     */
-    public Metadata extract()
-    {
-        return extract(new Metadata());
-    }
-
-    /**
      * Performs the Jpeg data extraction, adding found values to the specified
      * instance of <code>Metadata</code>.
      */
-    public Metadata extract(Metadata metadata)
+    public void extract(@NotNull final BufferReader reader, @NotNull Metadata metadata)
     {
-        if (_data==null) {
-            return metadata;
-        }
-
-        JpegDirectory directory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class);
+        JpegDirectory directory = metadata.getOrCreateDirectory(JpegDirectory.class);
 
         try {
             // data precision
-            int dataPrecision = get16Bits(JpegDirectory.TAG_JPEG_DATA_PRECISION);
+            int dataPrecision = reader.getUInt8(JpegDirectory.TAG_JPEG_DATA_PRECISION);
             directory.setInt(JpegDirectory.TAG_JPEG_DATA_PRECISION, dataPrecision);
 
             // process height
-            int height = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
+            int height = reader.getUInt16(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
             directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, height);
 
             // process width
-            int width = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
+            int width = reader.getUInt16(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
             directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, width);
 
             // number of components
-            int numberOfComponents = get16Bits(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS);
+            int numberOfComponents = reader.getUInt8(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS);
             directory.setInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, numberOfComponents);
 
@@ -101,46 +64,15 @@
             // 3 - Quantization table number
             int offset = 6;
-            for (int i=0; i<numberOfComponents; i++)
-            {
-                int componentId = get16Bits(offset++);
-                int samplingFactorByte = get16Bits(offset++);
-                int quantizationTableNumber = get16Bits(offset++);
+            for (int i = 0; i < numberOfComponents; i++) {
+                int componentId = reader.getUInt8(offset++);
+                int samplingFactorByte = reader.getUInt8(offset++);
+                int quantizationTableNumber = reader.getUInt8(offset++);
                 JpegComponent component = new JpegComponent(componentId, samplingFactorByte, quantizationTableNumber);
                 directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + i, component);
             }
 
-        } catch (MetadataException me) {
-            directory.addError("MetadataException: " + me);
+        } catch (BufferBoundsException ex) {
+            directory.addError(ex.getMessage());
         }
-
-        return metadata;
-    }
-
-    /**
-     * Returns an int calculated from two bytes of data at the specified offset (MSB, LSB).
-     * @param offset position within the data buffer to read first byte
-     * @return the 32 bit int value, between 0x0000 and 0xFFFF
-     */
-    private int get32Bits(int offset) throws MetadataException
-    {
-        if (offset+1>=_data.length) {
-            throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer");
-        }
-
-        return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255);
-    }
-
-    /**
-     * Returns an int calculated from one byte of data at the specified offset.
-     * @param offset position within the data buffer to read byte
-     * @return the 16 bit int value, between 0x00 and 0xFF
-     */
-    private int get16Bits(int offset) throws MetadataException
-    {
-        if (offset>=_data.length) {
-            throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer");
-        }
-
-        return (_data[offset] & 255);
     }
 }
