You are viewing a plain text version of this content. The canonical link for it is here.
Posted to sanselan-commits@incubator.apache.org by cm...@apache.org on 2008/07/27 17:42:06 UTC

svn commit: r680158 - in /incubator/sanselan/trunk/src: main/java/org/apache/sanselan/formats/jpeg/ main/java/org/apache/sanselan/formats/jpeg/xmp/ test/java/org/apache/sanselan/formats/jpeg/xmp/

Author: cmchen
Date: Sun Jul 27 10:42:05 2008
New Revision: 680158

URL: http://svn.apache.org/viewvc?rev=680158&view=rev
Log:
Began work on xmp support.  Added xmp-extraction to Jpeg parser.

Added:
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpParser.java   (with props)
    incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/
    incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpBaseTest.java   (with props)
    incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpDumpTest.java   (with props)
Modified:
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java

Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java?rev=680158&r1=680157&r2=680158&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java Sun Jul 27 10:42:05 2008
@@ -41,27 +41,25 @@
 import org.apache.sanselan.formats.jpeg.segments.SOFNSegment;
 import org.apache.sanselan.formats.jpeg.segments.Segment;
 import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
+import org.apache.sanselan.formats.jpeg.xmp.JpegXmpParser;
 import org.apache.sanselan.formats.tiff.TiffField;
 import org.apache.sanselan.formats.tiff.TiffImageMetadata;
 import org.apache.sanselan.formats.tiff.TiffImageParser;
 import org.apache.sanselan.formats.tiff.constants.TiffTagConstants;
 import org.apache.sanselan.util.Debug;
 
-public class JpegImageParser extends ImageParser
-		implements
-			JpegConstants,
-			TiffTagConstants
+public class JpegImageParser extends ImageParser implements JpegConstants,
+		TiffTagConstants
 {
 	public JpegImageParser()
 	{
 		setByteOrder(BYTE_ORDER_NETWORK);
-		//		setDebug(true);
+		// setDebug(true);
 	}
 
 	protected ImageFormat[] getAcceptedTypes()
 	{
-		return new ImageFormat[]{
-			ImageFormat.IMAGE_FORMAT_JPEG, //
+		return new ImageFormat[] { ImageFormat.IMAGE_FORMAT_JPEG, //
 		};
 	}
 
@@ -77,9 +75,7 @@
 
 	private static final String DEFAULT_EXTENSION = ".jpg";
 
-	public static final String AcceptedExtensions[] = {
-			".jpg", ".jpeg",
-	};
+	public static final String AcceptedExtensions[] = { ".jpg", ".jpeg", };
 
 	protected String[] getAcceptedExtensions()
 	{
@@ -114,8 +110,7 @@
 		final ArrayList result = new ArrayList();
 		final JpegImageParser parser = this;
 
-		JpegUtils.Visitor visitor = new JpegUtils.Visitor()
-		{
+		JpegUtils.Visitor visitor = new JpegUtils.Visitor() {
 			// return false to exit before reading image data.
 			public boolean beginSOS()
 			{
@@ -135,31 +130,29 @@
 				if (marker == 0xffd9)
 					return false;
 
-				//				Debug.debug("visitSegment marker", marker);
-				////				Debug.debug("visitSegment keepMarker(marker, markers)", keepMarker(marker, markers));
-				//				Debug.debug("visitSegment keepMarker(marker, markers)", keepMarker(marker, markers));
+				// Debug.debug("visitSegment marker", marker);
+				// // Debug.debug("visitSegment keepMarker(marker, markers)",
+				// keepMarker(marker, markers));
+				// Debug.debug("visitSegment keepMarker(marker, markers)",
+				// keepMarker(marker, markers));
 
 				if (!keepMarker(marker, markers))
 					return true;
 
 				if (marker == JPEG_APP13_Marker)
 				{
-					//					Debug.debug("app 13 segment data", segmentData.length);
+					// Debug.debug("app 13 segment data", segmentData.length);
 					result.add(new App13Segment(parser, marker, segmentData));
-				}
-				else if (marker == JPEG_APP2_Marker)
+				} else if (marker == JPEG_APP2_Marker)
 				{
 					result.add(new App2Segment(marker, segmentData));
-				}
-				else if (marker == JFIFMarker)
+				} else if (marker == JFIFMarker)
 				{
 					result.add(new JFIFSegment(marker, segmentData));
-				}
-				else if ((marker >= SOF0Marker) && (marker <= SOF15Marker))
+				} else if ((marker >= SOF0Marker) && (marker <= SOF15Marker))
 				{
 					result.add(new SOFNSegment(marker, segmentData));
-				}
-				else if ((marker >= JPEG_APP1_Marker)
+				} else if ((marker >= JPEG_APP1_Marker)
 						&& (marker <= JPEG_APP15_Marker))
 				{
 					result.add(new UnknownSegment(marker, segmentData));
@@ -185,8 +178,7 @@
 		try
 		{
 			return assembleSegments(v, false);
-		}
-		catch (ImageReadException e)
+		} catch (ImageReadException e)
 		{
 			return assembleSegments(v, true);
 		}
@@ -200,8 +192,8 @@
 
 		int markerCount = ((App2Segment) v.get(0)).num_markers;
 
-		//		if (permissive && (markerCount == 0))
-		//			markerCount = v.size();
+		// if (permissive && (markerCount == 0))
+		// markerCount = v.size();
 
 		if (v.size() != markerCount)
 			throw new ImageReadException("App2 Segments Missing.  Found: "
@@ -276,9 +268,8 @@
 	public byte[] getICCProfileBytes(ByteSource byteSource, Map params)
 			throws ImageReadException, IOException
 	{
-		ArrayList segments = readSegments(byteSource, new int[]{
-			JPEG_APP2_Marker,
-		}, false);
+		ArrayList segments = readSegments(byteSource,
+				new int[] { JPEG_APP2_Marker, }, false);
 
 		if (segments != null)
 		{
@@ -369,9 +360,9 @@
 		if (!params.containsKey(PARAM_KEY_READ_THUMBNAILS))
 			params.put(PARAM_KEY_READ_THUMBNAILS, Boolean.TRUE);
 
-		//		Debug.debug("read thumbs?", params.get(PARAM_KEY_READ_THUMBNAILS));
+		// Debug.debug("read thumbs?", params.get(PARAM_KEY_READ_THUMBNAILS));
 
-		//				Debug.debug("exif bytes", bytes.length);
+		// Debug.debug("exif bytes", bytes.length);
 
 		return (TiffImageMetadata) new TiffImageParser().getMetadata(bytes,
 				params);
@@ -380,9 +371,8 @@
 	public byte[] getExifRawData(ByteSource byteSource)
 			throws ImageReadException, IOException
 	{
-		ArrayList segments = readSegments(byteSource, new int[]{
-			JPEG_APP1_Marker,
-		}, false);
+		ArrayList segments = readSegments(byteSource,
+				new int[] { JPEG_APP1_Marker, }, false);
 
 		if ((segments == null) || (segments.size() < 1))
 			return null;
@@ -392,8 +382,8 @@
 			System.out.println("exif_segments.size" + ": "
 					+ exifSegments.size());
 
-		//		Debug.debug("segments", segments);
-		//		Debug.debug("exifSegments", exifSegments);
+		// Debug.debug("segments", segments);
+		// Debug.debug("exifSegments", exifSegments);
 
 		// TODO: concatenate if multiple segments, need example.
 		if (exifSegments.size() < 1)
@@ -406,9 +396,9 @@
 		GenericSegment segment = (GenericSegment) exifSegments.get(0);
 		byte bytes[] = segment.bytes;
 
-		//		byte head[] = readBytearray("exif head", bytes, 0, 6);
+		// byte head[] = readBytearray("exif head", bytes, 0, 6);
 		//
-		//		Debug.debug("head", head);
+		// Debug.debug("head", head);
 
 		return getByteArrayTail("trimmed exif bytes", bytes, 6);
 	}
@@ -416,12 +406,9 @@
 	public boolean hasExifSegment(ByteSource byteSource)
 			throws ImageReadException, IOException
 	{
-		final boolean result[] = {
-			false,
-		};
+		final boolean result[] = { false, };
 
-		JpegUtils.Visitor visitor = new JpegUtils.Visitor()
-		{
+		JpegUtils.Visitor visitor = new JpegUtils.Visitor() {
 			// return false to exit before reading image data.
 			public boolean beginSOS()
 			{
@@ -459,12 +446,106 @@
 		return result[0];
 	}
 
+	public boolean hasXmpSegment(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		final boolean result[] = { false, };
+
+		JpegUtils.Visitor visitor = new JpegUtils.Visitor() {
+			// return false to exit before reading image data.
+			public boolean beginSOS()
+			{
+				return false;
+			}
+
+			public void visitSOS(int marker, byte markerBytes[],
+					byte imageData[])
+			{
+			}
+
+			// return false to exit traversal.
+			public boolean visitSegment(int marker, byte markerBytes[],
+					int markerLength, byte markerLengthBytes[],
+					byte segmentData[]) throws ImageReadException, IOException
+			{
+				if (marker == 0xffd9)
+					return false;
+
+				if (marker == JPEG_APP1_Marker)
+				{
+					if (new JpegXmpParser().isXmpJpegSegment(segmentData))
+					{
+						result[0] = true;
+						return false;
+					}
+				}
+
+				return true;
+			}
+		};
+		new JpegUtils().traverseJFIF(byteSource, visitor);
+
+		return result[0];
+	}
+
+	/*
+	 * Locates the XMP XML if present.
+	 * 
+	 * returns null if no XMP segment is found.
+	 */
+	public String getXmpXml(ByteSource byteSource) throws ImageReadException,
+			IOException
+	{
+		final List result = new ArrayList();
+
+		JpegUtils.Visitor visitor = new JpegUtils.Visitor() {
+			// return false to exit before reading image data.
+			public boolean beginSOS()
+			{
+				return false;
+			}
+
+			public void visitSOS(int marker, byte markerBytes[],
+					byte imageData[])
+			{
+			}
+
+			// return false to exit traversal.
+			public boolean visitSegment(int marker, byte markerBytes[],
+					int markerLength, byte markerLengthBytes[],
+					byte segmentData[]) throws ImageReadException, IOException
+			{
+				if (marker == 0xffd9)
+					return false;
+
+				if (marker == JPEG_APP1_Marker)
+				{
+					if (new JpegXmpParser().isXmpJpegSegment(segmentData))
+					{
+						result.add(new JpegXmpParser()
+								.parseXmpJpegSegment(segmentData));
+						return false;
+					}
+				}
+
+				return true;
+			}
+		};
+		new JpegUtils().traverseJFIF(byteSource, visitor);
+
+		if (result.size() < 1)
+			return null;
+		if (result.size() > 1)
+			throw new ImageReadException(
+					"Jpeg file contains more than one XMP segment.");
+		return (String) result.get(0);
+	}
+
 	private JpegImageMetadata.Photoshop getPhotoshopMetadata(
 			ByteSource byteSource) throws ImageReadException, IOException
 	{
-		ArrayList segments = readSegments(byteSource, new int[]{
-			JPEG_APP13_Marker,
-		}, false);
+		ArrayList segments = readSegments(byteSource,
+				new int[] { JPEG_APP13_Marker, }, false);
 
 		if ((segments == null) || (segments.size() < 1))
 			return null;
@@ -487,12 +568,11 @@
 		return result;
 	}
 
-	public Dimension getImageSize(ByteSource byteSource,
-			Map params)
+	public Dimension getImageSize(ByteSource byteSource, Map params)
 			throws ImageReadException, IOException
 	{
-		ArrayList segments = readSegments(byteSource, new int[]{
-				//			kJFIFMarker,
+		ArrayList segments = readSegments(byteSource, new int[] {
+				// kJFIFMarker,
 				SOF0Marker,
 
 				SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker, SOF6Marker,
@@ -525,10 +605,10 @@
 	public ImageInfo getImageInfo(ByteSource byteSource, Map params)
 			throws ImageReadException, IOException
 	{
-		//		ArrayList allSegments = readSegments(byteSource, null, false);
+		// ArrayList allSegments = readSegments(byteSource, null, false);
 
-		ArrayList SOF_segments = readSegments(byteSource, new int[]{
-				//				kJFIFMarker,
+		ArrayList SOF_segments = readSegments(byteSource, new int[] {
+				// kJFIFMarker,
 
 				SOF0Marker, SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker,
 				SOF6Marker, SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker,
@@ -539,16 +619,16 @@
 		if (SOF_segments == null)
 			throw new ImageReadException("No SOFN Data Found.");
 
-		//		if (SOF_segments.size() != 1)
-		//			System.out.println("Incoherent SOFN Data Found: "
-		//					+ SOF_segments.size());
+		// if (SOF_segments.size() != 1)
+		// System.out.println("Incoherent SOFN Data Found: "
+		// + SOF_segments.size());
 
-		ArrayList jfifSegments = readSegments(byteSource, new int[]{
-			JFIFMarker,
-		}, true);
+		ArrayList jfifSegments = readSegments(byteSource,
+				new int[] { JFIFMarker, }, true);
 
 		SOFNSegment fSOFNSegment = (SOFNSegment) SOF_segments.get(0);
-		//		SOFNSegment fSOFNSegment = (SOFNSegment) findSegment(segments, SOFNmarkers);
+		// SOFNSegment fSOFNSegment = (SOFNSegment) findSegment(segments,
+		// SOFNmarkers);
 
 		if (fSOFNSegment == null)
 			throw new ImageReadException("No SOFN Data Found.");
@@ -561,14 +641,14 @@
 		if ((jfifSegments != null) && (jfifSegments.size() > 0))
 			jfifSegment = (JFIFSegment) jfifSegments.get(0);
 
-		//		JFIFSegment fTheJFIFSegment = (JFIFSegment) findSegment(segments,
-		//				kJFIFMarker);
+		// JFIFSegment fTheJFIFSegment = (JFIFSegment) findSegment(segments,
+		// kJFIFMarker);
 
 		double x_density = -1.0;
 		double y_density = -1.0;
 		double units_per_inch = -1.0;
-		//		int JFIF_major_version;
-		//		int JFIF_minor_version;
+		// int JFIF_major_version;
+		// int JFIF_minor_version;
 		String FormatDetails;
 
 		if (jfifSegment != null)
@@ -576,27 +656,26 @@
 			x_density = jfifSegment.xDensity;
 			y_density = jfifSegment.yDensity;
 			int density_units = jfifSegment.densityUnits;
-			//			JFIF_major_version = fTheJFIFSegment.JFIF_major_version;
-			//			JFIF_minor_version = fTheJFIFSegment.JFIF_minor_version;
+			// JFIF_major_version = fTheJFIFSegment.JFIF_major_version;
+			// JFIF_minor_version = fTheJFIFSegment.JFIF_minor_version;
 
 			FormatDetails = "Jpeg/JFIF v." + jfifSegment.jfifMajorVersion + "."
 					+ jfifSegment.jfifMinorVersion;
 
 			switch (density_units)
 			{
-				case 0 :
-					break;
-				case 1 : // inches
-					units_per_inch = 1.0;
-					break;
-				case 2 : // cms
-					units_per_inch = 2.54;
-					break;
-				default :
-					break;
+			case 0:
+				break;
+			case 1: // inches
+				units_per_inch = 1.0;
+				break;
+			case 2: // cms
+				units_per_inch = 2.54;
+				break;
+			default:
+				break;
 			}
-		}
-		else
+		} else
 		{
 			JpegImageMetadata metadata = (JpegImageMetadata) getMetadata(
 					byteSource, params);
@@ -625,16 +704,16 @@
 
 						switch (density_units)
 						{
-							case 1 :
-								break;
-							case 2 : // inches
-								units_per_inch = 1.0;
-								break;
-							case 3 : // cms
-								units_per_inch = 2.54;
-								break;
-							default :
-								break;
+						case 1:
+							break;
+						case 2: // inches
+							units_per_inch = 1.0;
+							break;
+						case 3: // cms
+							units_per_inch = 2.54;
+							break;
+						default:
+							break;
 						}
 					}
 
@@ -698,171 +777,174 @@
 		return result;
 	}
 
-	//	public ImageInfo getImageInfo(ByteSource byteSource, Map params)
-	//			throws ImageReadException, IOException
-	//	{
-	//
-	//		ArrayList allSegments = readSegments(byteSource, null, false);
-	//
-	//		final int SOF_MARKERS[] = new int[]{
-	//				SOF0Marker, SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker,
-	//				SOF6Marker, SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker,
-	//				SOF13Marker, SOF14Marker, SOF15Marker,
-	//		};
-	//
-	//		ArrayList sofMarkers = new ArrayList();
-	//		for(int i=0;i<SOF_MARKERS.length;i++)
-	//			sofMarkers.add(new Integer(SOF_MARKERS[i]));
-	//		ArrayList SOFSegments = filterSegments(allSegments, sofMarkers);
-	//		if (SOFSegments == null || SOFSegments.size()<1)
-	//			throw new ImageReadException("No SOFN Data Found.");
-	//
-	//		List jfifMarkers = new ArrayList();
-	//		jfifMarkers.add(new Integer(JFIFMarker));
-	//		ArrayList jfifSegments = filterSegments(allSegments, jfifMarkers);
-	//
-	//		SOFNSegment firstSOFNSegment = (SOFNSegment) SOFSegments.get(0);
-	//
-	//		int Width = firstSOFNSegment.width;
-	//		int Height = firstSOFNSegment.height;
-	//
-	//		JFIFSegment jfifSegment = null;
-	//
-	//		if (jfifSegments != null && jfifSegments.size() > 0)
-	//			jfifSegment = (JFIFSegment) jfifSegments.get(0);
-	//
-	//		double x_density = -1.0;
-	//		double y_density = -1.0;
-	//		double units_per_inch = -1.0;
-	//		//		int JFIF_major_version;
-	//		//		int JFIF_minor_version;
-	//		String FormatDetails;
-	//
-	//		if (jfifSegment != null)
-	//		{
-	//			x_density = jfifSegment.xDensity;
-	//			y_density = jfifSegment.yDensity;
-	//			int density_units = jfifSegment.densityUnits;
-	//			//			JFIF_major_version = fTheJFIFSegment.JFIF_major_version;
-	//			//			JFIF_minor_version = fTheJFIFSegment.JFIF_minor_version;
-	//
-	//			FormatDetails = "Jpeg/JFIF v." + jfifSegment.jfifMajorVersion
-	//					+ "." + jfifSegment.jfifMinorVersion;
-	//
-	//			switch (density_units)
-	//			{
-	//				case 0 :
-	//					break;
-	//				case 1 : // inches
-	//					units_per_inch = 1.0;
-	//					break;
-	//				case 2 : // cms
-	//					units_per_inch = 2.54;
-	//					break;
-	//				default :
-	//					break;
-	//			}
-	//		}
-	//		else
-	//		{
-	//			JpegImageMetadata metadata = (JpegImageMetadata) getMetadata(byteSource, params);
-	//
-	//			{
-	//				TiffField field = metadata
-	//						.findEXIFValue(TiffField.TIFF_TAG_XRESOLUTION);
-	//				if (field == null)
-	//					throw new ImageReadException("No XResolution");
-	//
-	//				x_density = ((Number) field.getValue()).doubleValue();
-	//			}
-	//			{
-	//				TiffField field = metadata
-	//						.findEXIFValue(TiffField.TIFF_TAG_YRESOLUTION);
-	//				if (field == null)
-	//					throw new ImageReadException("No YResolution");
-	//
-	//				y_density = ((Number) field.getValue()).doubleValue();
-	//			}
-	//			{
-	//				TiffField field = metadata
-	//						.findEXIFValue(TiffField.TIFF_TAG_RESOLUTION_UNIT);
-	//				if (field == null)
-	//					throw new ImageReadException("No ResolutionUnits");
-	//
-	//				int density_units = ((Number) field.getValue()).intValue();
-	//
-	//				switch (density_units)
-	//				{
-	//					case 1 :
-	//						break;
-	//					case 2 : // inches
-	//						units_per_inch = 1.0;
-	//						break;
-	//					case 3 : // cms
-	//						units_per_inch = 2.54;
-	//						break;
-	//					default :
-	//						break;
-	//				}
-	//
-	//			}
-	//
-	//			FormatDetails = "Jpeg/DCM";
-	//
-	//		}
-	//
-	//		int PhysicalHeightDpi = -1;
-	//		float PhysicalHeightInch = -1;
-	//		int PhysicalWidthDpi = -1;
-	//		float PhysicalWidthInch = -1;
-	//
-	//		if (units_per_inch > 0)
-	//		{
-	//			PhysicalWidthDpi = (int) Math.round((double) x_density
-	//					/ units_per_inch);
-	//			PhysicalWidthInch = (float) ((double) Width / (x_density * units_per_inch));
-	//			PhysicalHeightDpi = (int) Math.round((double) y_density
-	//					* units_per_inch);
-	//			PhysicalHeightInch = (float) ((double) Height / (y_density * units_per_inch));
-	//		}
-	//
-	//		ArrayList Comments = new ArrayList();
-	//		// TODO: comments...
-	//
-	//		int Number_of_components = firstSOFNSegment.numberOfComponents;
-	//		int Precision = firstSOFNSegment.precision;
-	//
-	//		int BitsPerPixel = Number_of_components * Precision;
-	//		ImageFormat Format = ImageFormat.IMAGE_FORMAT_JPEG;
-	//		String FormatName = "JPEG (Joint Photographic Experts Group) Format";
-	//		String MimeType = "image/jpeg";
-	//		// we ought to count images, but don't yet.
-	//		int NumberOfImages = -1;
-	//		// not accurate ... only reflects first
-	//		boolean isProgressive = firstSOFNSegment.marker == SOF2Marker;
-	//
-	//		boolean isTransparent = false; // TODO: inaccurate.
-	//		boolean usesPalette = false; // TODO: inaccurate.
-	//		int ColorType;
-	//		if (Number_of_components == 1)
-	//			ColorType = ImageInfo.COLOR_TYPE_BW;
-	//		else if (Number_of_components == 3)
-	//			ColorType = ImageInfo.COLOR_TYPE_RGB;
-	//		else if (Number_of_components == 4)
-	//			ColorType = ImageInfo.COLOR_TYPE_CMYK;
-	//		else
-	//			ColorType = ImageInfo.COLOR_TYPE_UNKNOWN;
-	//
-	//		String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_JPEG;
-	//
-	//		ImageInfo result = new ImageInfo(FormatDetails, BitsPerPixel, Comments,
-	//				Format, FormatName, Height, MimeType, NumberOfImages,
-	//				PhysicalHeightDpi, PhysicalHeightInch, PhysicalWidthDpi,
-	//				PhysicalWidthInch, Width, isProgressive, isTransparent,
-	//				usesPalette, ColorType, compressionAlgorithm);
+	// public ImageInfo getImageInfo(ByteSource byteSource, Map params)
+	// throws ImageReadException, IOException
+	// {
+	//
+	// ArrayList allSegments = readSegments(byteSource, null, false);
+	//
+	// final int SOF_MARKERS[] = new int[]{
+	// SOF0Marker, SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker,
+	// SOF6Marker, SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker,
+	// SOF13Marker, SOF14Marker, SOF15Marker,
+	// };
+	//
+	// ArrayList sofMarkers = new ArrayList();
+	// for(int i=0;i<SOF_MARKERS.length;i++)
+	// sofMarkers.add(new Integer(SOF_MARKERS[i]));
+	// ArrayList SOFSegments = filterSegments(allSegments, sofMarkers);
+	// if (SOFSegments == null || SOFSegments.size()<1)
+	// throw new ImageReadException("No SOFN Data Found.");
+	//
+	// List jfifMarkers = new ArrayList();
+	// jfifMarkers.add(new Integer(JFIFMarker));
+	// ArrayList jfifSegments = filterSegments(allSegments, jfifMarkers);
+	//
+	// SOFNSegment firstSOFNSegment = (SOFNSegment) SOFSegments.get(0);
+	//
+	// int Width = firstSOFNSegment.width;
+	// int Height = firstSOFNSegment.height;
+	//
+	// JFIFSegment jfifSegment = null;
+	//
+	// if (jfifSegments != null && jfifSegments.size() > 0)
+	// jfifSegment = (JFIFSegment) jfifSegments.get(0);
+	//
+	// double x_density = -1.0;
+	// double y_density = -1.0;
+	// double units_per_inch = -1.0;
+	// // int JFIF_major_version;
+	// // int JFIF_minor_version;
+	// String FormatDetails;
+	//
+	// if (jfifSegment != null)
+	// {
+	// x_density = jfifSegment.xDensity;
+	// y_density = jfifSegment.yDensity;
+	// int density_units = jfifSegment.densityUnits;
+	// // JFIF_major_version = fTheJFIFSegment.JFIF_major_version;
+	// // JFIF_minor_version = fTheJFIFSegment.JFIF_minor_version;
+	//
+	// FormatDetails = "Jpeg/JFIF v." + jfifSegment.jfifMajorVersion
+	// + "." + jfifSegment.jfifMinorVersion;
+	//
+	// switch (density_units)
+	// {
+	// case 0 :
+	// break;
+	// case 1 : // inches
+	// units_per_inch = 1.0;
+	// break;
+	// case 2 : // cms
+	// units_per_inch = 2.54;
+	// break;
+	// default :
+	// break;
+	// }
+	// }
+	// else
+	// {
+	// JpegImageMetadata metadata = (JpegImageMetadata) getMetadata(byteSource,
+	// params);
+	//
+	// {
+	// TiffField field = metadata
+	// .findEXIFValue(TiffField.TIFF_TAG_XRESOLUTION);
+	// if (field == null)
+	// throw new ImageReadException("No XResolution");
+	//
+	// x_density = ((Number) field.getValue()).doubleValue();
+	// }
+	// {
+	// TiffField field = metadata
+	// .findEXIFValue(TiffField.TIFF_TAG_YRESOLUTION);
+	// if (field == null)
+	// throw new ImageReadException("No YResolution");
+	//
+	// y_density = ((Number) field.getValue()).doubleValue();
+	// }
+	// {
+	// TiffField field = metadata
+	// .findEXIFValue(TiffField.TIFF_TAG_RESOLUTION_UNIT);
+	// if (field == null)
+	// throw new ImageReadException("No ResolutionUnits");
+	//
+	// int density_units = ((Number) field.getValue()).intValue();
+	//
+	// switch (density_units)
+	// {
+	// case 1 :
+	// break;
+	// case 2 : // inches
+	// units_per_inch = 1.0;
+	// break;
+	// case 3 : // cms
+	// units_per_inch = 2.54;
+	// break;
+	// default :
+	// break;
+	// }
+	//
+	// }
+	//
+	// FormatDetails = "Jpeg/DCM";
+	//
+	// }
+	//
+	// int PhysicalHeightDpi = -1;
+	// float PhysicalHeightInch = -1;
+	// int PhysicalWidthDpi = -1;
+	// float PhysicalWidthInch = -1;
+	//
+	// if (units_per_inch > 0)
+	// {
+	// PhysicalWidthDpi = (int) Math.round((double) x_density
+	// / units_per_inch);
+	// PhysicalWidthInch = (float) ((double) Width / (x_density *
+	// units_per_inch));
+	// PhysicalHeightDpi = (int) Math.round((double) y_density
+	// * units_per_inch);
+	// PhysicalHeightInch = (float) ((double) Height / (y_density *
+	// units_per_inch));
+	// }
+	//
+	// ArrayList Comments = new ArrayList();
+	// // TODO: comments...
+	//
+	// int Number_of_components = firstSOFNSegment.numberOfComponents;
+	// int Precision = firstSOFNSegment.precision;
+	//
+	// int BitsPerPixel = Number_of_components * Precision;
+	// ImageFormat Format = ImageFormat.IMAGE_FORMAT_JPEG;
+	// String FormatName = "JPEG (Joint Photographic Experts Group) Format";
+	// String MimeType = "image/jpeg";
+	// // we ought to count images, but don't yet.
+	// int NumberOfImages = -1;
+	// // not accurate ... only reflects first
+	// boolean isProgressive = firstSOFNSegment.marker == SOF2Marker;
+	//
+	// boolean isTransparent = false; // TODO: inaccurate.
+	// boolean usesPalette = false; // TODO: inaccurate.
+	// int ColorType;
+	// if (Number_of_components == 1)
+	// ColorType = ImageInfo.COLOR_TYPE_BW;
+	// else if (Number_of_components == 3)
+	// ColorType = ImageInfo.COLOR_TYPE_RGB;
+	// else if (Number_of_components == 4)
+	// ColorType = ImageInfo.COLOR_TYPE_CMYK;
+	// else
+	// ColorType = ImageInfo.COLOR_TYPE_UNKNOWN;
+	//
+	// String compressionAlgorithm = ImageInfo.COMPRESSION_ALGORITHM_JPEG;
+	//
+	// ImageInfo result = new ImageInfo(FormatDetails, BitsPerPixel, Comments,
+	// Format, FormatName, Height, MimeType, NumberOfImages,
+	// PhysicalHeightDpi, PhysicalHeightInch, PhysicalWidthDpi,
+	// PhysicalWidthInch, Width, isProgressive, isTransparent,
+	// usesPalette, ColorType, compressionAlgorithm);
 	//
-	//		return result;
-	//	}
+	// return result;
+	// }
 
 	public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
 			throws ImageReadException, IOException
@@ -891,7 +973,7 @@
 				Segment segment = (Segment) segments.get(d);
 
 				NumberFormat nf = NumberFormat.getIntegerInstance();
-				//			this.debugNumber("found, marker: ", marker, 4);
+				// this.debugNumber("found, marker: ", marker, 4);
 				pw.println(d + ": marker: "
 						+ Integer.toHexString(segment.marker) + ", "
 						+ segment.getDescription() + " (length: "

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpParser.java?rev=680158&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpParser.java Sun Jul 27 10:42:05 2008
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *      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.
+ */
+
+package org.apache.sanselan.formats.jpeg.xmp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.SanselanConstants;
+import org.apache.sanselan.common.BinaryFileParser;
+import org.apache.sanselan.common.BinaryOutputStream;
+import org.apache.sanselan.util.Debug;
+import org.apache.sanselan.util.ParamMap;
+
+public class JpegXmpParser extends BinaryFileParser
+{
+
+	public JpegXmpParser()
+	{
+		setByteOrder(BYTE_ORDER_NETWORK);
+	}
+
+	public static final String XMP_NAMESPACE_URI = "http://ns.adobe.com/xap/1.0/";
+
+	public static final byte XMP_IDENTIFIER[] = { //
+	0x68, // h
+			0x74, // t
+			0x74, // t
+			0x70, // p
+			0x3A, // :
+			0x2F, // /
+			0x2F, // /
+			0x6E, // n
+			0x73, // s
+			0x2E, // .
+			0x61, // a
+			0x64, // d
+			0x6F, // o
+			0x62, // b
+			0x65, // e
+			0x2E, // .
+			0x63, // c
+			0x6F, // o
+			0x6D, // m
+			0x2F, // /
+			0x78, // x
+			0x61, // a
+			0x70, // p
+			0x2F, // /
+			0x31, // 1
+			0x2E, // .
+			0x30, // 0
+			0x2F, // /
+			0, // 0-terminated us-ascii string.
+	};
+
+	public boolean isXmpJpegSegment(byte segmentData[])
+	{
+		int index = 0;
+
+		if (segmentData.length < XMP_IDENTIFIER.length)
+			return false;
+		for (; index < XMP_IDENTIFIER.length; index++)
+			if (segmentData[index] < XMP_IDENTIFIER[index])
+				return false;
+
+		return true;
+	}
+
+	public String parseXmpJpegSegment(byte segmentData[])
+			throws ImageReadException
+	{
+		int index = 0;
+
+		if (segmentData.length < XMP_IDENTIFIER.length)
+			throw new ImageReadException("Invalid JPEG XMP Segment.");
+		for (; index < XMP_IDENTIFIER.length; index++)
+			if (segmentData[index] < XMP_IDENTIFIER[index])
+				throw new ImageReadException("Invalid JPEG XMP Segment.");
+
+		try
+		{
+			// segment data is UTF-8 encoded xml.
+			String xml = new String(segmentData, index, segmentData.length
+					- index, "utf-8");
+			return xml;
+		} catch (UnsupportedEncodingException e)
+		{
+			throw new ImageReadException("Invalid JPEG XMP Segment.");
+		}
+	}
+
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpBaseTest.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpBaseTest.java?rev=680158&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpBaseTest.java (added)
+++ incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpBaseTest.java Sun Jul 27 10:42:05 2008
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *      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.
+ */
+
+package org.apache.sanselan.formats.jpeg.xmp;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.SanselanTest;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.common.byteSources.ByteSourceFile;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public abstract class JpegXmpBaseTest extends SanselanTest
+{
+
+	protected static boolean hasJpegXmpData(File file) throws IOException,
+			ImageReadException
+	{
+		if (!file.getName().toLowerCase().endsWith(".jpg"))
+			return false;
+		//ImageFormat format = Sanselan.guessFormat(file);
+		//if (format != ImageFormat.IMAGE_FORMAT_JPEG)
+		//	return false;
+
+		//		Debug.debug("possible file", file);
+
+		try
+		{
+			ByteSource byteSource = new ByteSourceFile(file);
+			return new JpegImageParser().hasXmpSegment(byteSource);
+		}
+		catch (Exception e)
+		{
+			//			Debug.debug("Error file", file.getAbsoluteFile());
+			//			Debug.debug(e, 4);
+			return false;
+		}
+	}
+
+	private static final ImageFilter HAS_JPEG_XMP_IMAGE_FILTER = new ImageFilter()
+	{
+		public boolean accept(File file) throws IOException, ImageReadException
+		{
+			return hasJpegXmpData(file);
+		}
+	};
+
+//	private static final ImageFilter JPEG_IMAGE_FILTER = new ImageFilter()
+//	{
+//		public boolean accept(File file) throws IOException, ImageReadException
+//		{
+//			return file.getName().toLowerCase().endsWith(".jpg");
+//		}
+//	};
+
+	protected File getImageWithIptcData() throws IOException,
+			ImageReadException
+	{
+		return getTestImage(HAS_JPEG_XMP_IMAGE_FILTER);
+	}
+
+	protected List getImagesWithIptcData() throws IOException,
+			ImageReadException
+	{
+		return getTestImages(HAS_JPEG_XMP_IMAGE_FILTER);
+	}
+
+	protected List getImagesWithIptcData(int max) throws IOException,
+			ImageReadException
+	{
+		return getTestImages(HAS_JPEG_XMP_IMAGE_FILTER, max);
+	}
+
+//	protected File getJpegImage() throws IOException, ImageReadException
+//	{
+//		return getTestImage(JPEG_IMAGE_FILTER);
+//	}
+//
+//	protected List getJpegImages() throws IOException, ImageReadException
+//	{
+//		return getTestImages(JPEG_IMAGE_FILTER);
+//	}
+//
+//	protected List getJpegImages(int max) throws IOException,
+//			ImageReadException
+//	{
+//		return getTestImages(JPEG_IMAGE_FILTER, max);
+//	}
+
+}

Propchange: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpBaseTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpDumpTest.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpDumpTest.java?rev=680158&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpDumpTest.java (added)
+++ incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpDumpTest.java Sun Jul 27 10:42:05 2008
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *      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.
+ */
+
+package org.apache.sanselan.formats.jpeg.xmp;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.common.byteSources.ByteSourceFile;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+import org.apache.sanselan.util.Debug;
+
+public class JpegXmpDumpTest extends JpegXmpBaseTest
+{
+
+	public void test() throws IOException, ImageReadException,
+			ImageWriteException
+	{
+		List images = getImagesWithIptcData();
+		for (int i = 0; i < images.size(); i++)
+		{
+			if (i % 10 == 0)
+				Debug.purgeMemory();
+
+			File imageFile = (File) images.get(i);
+			Debug.debug("imageFile", imageFile);
+			Debug.debug();
+
+			ByteSource byteSource = new ByteSourceFile(imageFile);
+			String xmpXml = new JpegImageParser().getXmpXml(byteSource);
+			assertNotNull(xmpXml);
+
+			Debug.debug("xmpXml", xmpXml);
+			Debug.debug();
+		}
+	}
+
+}

Propchange: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/xmp/JpegXmpDumpTest.java
------------------------------------------------------------------------------
    svn:eol-style = native