/** End of image marker */\r
private static final byte MARKER_EOI = (byte)0xD9;\r
\r
- /** APP0 Jpeg segment identifier -- Jfif data. */\r
- public static final byte SEGMENT_APP0 = (byte)0xE0;\r
/** APP1 Jpeg segment identifier -- where Exif data is kept. */\r
- public static final byte SEGMENT_APP1 = (byte)0xE1;\r
- /** APP2 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP2 = (byte)0xE2;\r
- /** APP3 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP3 = (byte)0xE3;\r
- /** APP4 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP4 = (byte)0xE4;\r
- /** APP5 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP5 = (byte)0xE5;\r
- /** APP6 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP6 = (byte)0xE6;\r
- /** APP7 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP7 = (byte)0xE7;\r
- /** APP8 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP8 = (byte)0xE8;\r
- /** APP9 Jpeg segment identifier. */\r
- public static final byte SEGMENT_APP9 = (byte)0xE9;\r
- /** APPA Jpeg segment identifier -- can hold Unicode comments. */\r
- public static final byte SEGMENT_APPA = (byte)0xEA;\r
- /** APPB Jpeg segment identifier. */\r
- public static final byte SEGMENT_APPB = (byte)0xEB;\r
- /** APPC Jpeg segment identifier. */\r
- public static final byte SEGMENT_APPC = (byte)0xEC;\r
- /** APPD Jpeg segment identifier -- IPTC data in here. */\r
- public static final byte SEGMENT_APPD = (byte)0xED;\r
- /** APPE Jpeg segment identifier. */\r
- public static final byte SEGMENT_APPE = (byte)0xEE;\r
- /** APPF Jpeg segment identifier. */\r
- public static final byte SEGMENT_APPF = (byte)0xEF;\r
- /** Start Of Image segment identifier. */\r
- public static final byte SEGMENT_SOI = (byte)0xD8;\r
- /** Define Quantization Table segment identifier. */\r
- public static final byte SEGMENT_DQT = (byte)0xDB;\r
- /** Define Huffman Table segment identifier. */\r
- public static final byte SEGMENT_DHT = (byte)0xC4;\r
- /** Start-of-Frame Zero segment identifier. */\r
- public static final byte SEGMENT_SOF0 = (byte)0xC0;\r
- /** Jpeg comment segment identifier. */\r
- public static final byte SEGMENT_COM = (byte)0xFE;\r
+ private static final byte SEGMENT_APP1 = (byte)0xE1;\r
\r
/** Magic numbers to mark the beginning of all Jpegs */\r
private static final int MAGIC_JPEG_BYTE_1 = 0xFF;\r
private static final int MAGIC_JPEG_BYTE_2 = 0xD8;\r
\r
\r
+ /**\r
+ * Get the Exif data segment for the specified file\r
+ * @param inFile File to read\r
+ * @return Exif data segment as byte array\r
+ * @throws JpegException on file read errors or exif data errors\r
+ */\r
+ public static byte[] readExifSegment(File inFile) throws JpegException\r
+ {\r
+ JpegSegmentData data = readSegments(inFile);\r
+ return data.getSegment(SEGMENT_APP1);\r
+ }\r
+\r
+\r
/**\r
* Obtain the Jpeg segment data from the specified file\r
* @param inFile File to read\r
* @return Jpeg segment data from file\r
* @throws JpegException on file read errors or exif data errors\r
*/\r
- public static JpegSegmentData readSegments(File inFile) throws JpegException\r
+ private static JpegSegmentData readSegments(File inFile) throws JpegException\r
{\r
JpegSegmentData segmentData = new JpegSegmentData();\r
-\r
BufferedInputStream bStream = null;\r
\r
try\r
{\r
bStream = new BufferedInputStream(new FileInputStream(inFile));\r
- int offset = 0;\r
// first two bytes should be jpeg magic number\r
- int magic1 = bStream.read() & 0xFF;\r
- int magic2 = bStream.read() & 0xFF;\r
- checkMagicNumbers(magic1, magic2);\r
+ final int magic1 = bStream.read() & 0xFF;\r
+ final int magic2 = bStream.read() & 0xFF;\r
+ if (magic1 != MAGIC_JPEG_BYTE_1 || magic2 != MAGIC_JPEG_BYTE_2) {\r
+ throw new JpegException("not a jpeg file");\r
+ }\r
\r
- offset += 2;\r
// Loop around segments found\r
+ boolean foundExif = false;\r
do\r
{\r
// next byte is 0xFF\r
byte segmentIdentifier = (byte) (bStream.read() & 0xFF);\r
if ((segmentIdentifier & 0xFF) != 0xFF)\r
{\r
- throw new JpegException("expected jpeg segment start identifier 0xFF at offset "\r
- + offset + ", not 0x" + Integer.toHexString(segmentIdentifier & 0xFF));\r
+ throw new JpegException("expected jpeg segment start 0xFF, not 0x"\r
+ + Integer.toHexString(segmentIdentifier & 0xFF));\r
}\r
- offset++;\r
// next byte is <segment-marker>\r
byte thisSegmentMarker = (byte) (bStream.read() & 0xFF);\r
- offset++;\r
// next 2-bytes are <segment-size>: [high-byte] [low-byte]\r
byte[] segmentLengthBytes = new byte[2];\r
bStream.read(segmentLengthBytes, 0, 2);\r
- offset += 2;\r
int segmentLength = ((segmentLengthBytes[0] << 8) & 0xFF00) | (segmentLengthBytes[1] & 0xFF);\r
// segment length includes size bytes, so subtract two\r
segmentLength -= 2;\r
else if (segmentLength < 0)\r
throw new JpegException("segment size would be less than zero");\r
byte[] segmentBytes = new byte[segmentLength];\r
- bStream.read(segmentBytes, 0, segmentLength);\r
- offset += segmentLength;\r
+ int bytesRead = bStream.read(segmentBytes, 0, segmentLength);\r
+ // Bail if not all bytes read in one go - otherwise following sections will be out of step\r
+ if (bytesRead != segmentLength) {\r
+ throw new JpegException("Tried to read " + segmentLength + " bytes but only got " + bytesRead);\r
+ }\r
if ((thisSegmentMarker & 0xFF) == (SEGMENT_SOS & 0xFF))\r
{\r
// The 'Start-Of-Scan' segment comes last so break out of loop\r
{\r
segmentData.addSegment(thisSegmentMarker, segmentBytes);\r
}\r
- // loop through to the next segment\r
+ // loop through to the next segment if exif hasn't already been found\r
+ foundExif = (thisSegmentMarker == SEGMENT_APP1);\r
}\r
- while (true);\r
+ while (!foundExif);\r
}\r
catch (FileNotFoundException fnfe)\r
{\r
// Return the result\r
return segmentData;\r
}\r
-\r
-\r
- /**\r
- * Helper method that validates the Jpeg file's magic number.\r
- * @param inMagic1 first half of magic number\r
- * @param inMagic2 second half of magic number\r
- * @throws JpegException if numbers do not match magic numbers expected\r
- */\r
- private static void checkMagicNumbers(int inMagic1, int inMagic2) throws JpegException\r
- {\r
- if (inMagic1 != MAGIC_JPEG_BYTE_1 || inMagic2 != MAGIC_JPEG_BYTE_2)\r
- {\r
- throw new JpegException("not a jpeg file");\r
- }\r
- }\r
-}
\ No newline at end of file
+}\r