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 2007/11/29 02:27:15 UTC

svn commit: r599250 [6/15] - in /incubator/sanselan/trunk/src/main/java/org: apache/sanselan/ apache/sanselan/color/ apache/sanselan/common/ apache/sanselan/common/byteSources/ apache/sanselan/common/mylzw/ apache/sanselan/formats/bmp/ apache/sanselan/...

Added: 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=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/JpegImageParser.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,727 @@
+/*
+ * 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;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.text.NumberFormat;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageFormat;
+import org.apache.sanselan.ImageInfo;
+import org.apache.sanselan.ImageParser;
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.common.IImageMetadata;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.formats.jpeg.segments.App13Segment;
+import org.apache.sanselan.formats.jpeg.segments.App2Segment;
+import org.apache.sanselan.formats.jpeg.segments.GenericSegment;
+import org.apache.sanselan.formats.jpeg.segments.JFIFSegment;
+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.tiff.TiffField;
+import org.apache.sanselan.formats.tiff.TiffImageMetadata;
+import org.apache.sanselan.formats.tiff.TiffImageParser;
+import org.apache.sanselan.util.Debug;
+
+public class JpegImageParser extends ImageParser implements JpegConstants
+{
+	public JpegImageParser()
+	{
+		setByteOrder(BYTE_ORDER_NETWORK);
+		//		setDebug(true);
+	}
+
+	protected ImageFormat[] getAcceptedTypes()
+	{
+		return new ImageFormat[]{
+			ImageFormat.IMAGE_FORMAT_JPEG, //
+		};
+	}
+
+	public String getName()
+	{
+		return "Jpeg-Custom";
+	}
+
+	public String getDefaultExtension()
+	{
+		return DEFAULT_EXTENSION;
+	}
+
+	private static final String DEFAULT_EXTENSION = ".jpg";
+
+	public static final String AcceptedExtensions[] = {
+			".jpg", ".jpeg",
+	};
+
+	protected String[] getAcceptedExtensions()
+	{
+		return AcceptedExtensions;
+	}
+
+	public final BufferedImage getBufferedImage(ByteSource byteSource,
+			Map params) throws ImageReadException, IOException
+	{
+		throw new ImageReadException(
+				"Sanselan cannot read or write JPEG images.");
+	}
+
+	private boolean keepMarker(int marker, int markers[])
+	{
+		if (markers == null)
+			return true;
+
+		for (int i = 0; i < markers.length; i++)
+		{
+			if (markers[i] == marker)
+				return true;
+		}
+
+		return false;
+	}
+
+	private Vector readMarkers(InputStream is, int markers[],
+			boolean return_after_first, boolean readEverything)
+			throws ImageReadException, IOException
+	{
+		Vector result = new Vector();
+
+		for (int markerCount = 0; true; markerCount++)
+		{
+			int marker = read2Bytes("marker", is, "Not a Valid JPEG File");
+
+			if (marker == 0xffd9)
+				break;
+			else
+			{
+
+				int markerLength = read2Bytes("markerLength", is,
+						"Not a Valid JPEG File");
+
+				if (keepMarker(marker, markers))
+				{
+					if (marker == JPEG_APP13_Marker)
+					{
+						result.add(new App13Segment(this, marker,
+								markerLength - 2, is));
+					}
+					else if (marker == JPEG_APP2_Marker)
+					{
+						result
+								.add(new App2Segment(marker, markerLength - 2,
+										is));
+					}
+					//					else if (marker == JPEG_APP14_Marker)
+					//					{
+					//						result.add(new Segment(markerLength - 2, is));
+					//					}
+					else if (marker == JFIFMarker)
+					{
+						result
+								.add(new JFIFSegment(marker, markerLength - 2,
+										is));
+					}
+					else if ((marker >= SOF0Marker) && (marker <= SOF15Marker))
+					{
+						result
+								.add(new SOFNSegment(marker, markerLength - 2,
+										is));
+					}
+					else if ((marker >= JPEG_APP1_Marker)
+							&& (marker <= JPEG_APP15_Marker))
+					{
+						result.add(new UnknownSegment(marker, markerLength - 2,
+								is));
+					}
+					else if (marker == SOS_Marker)
+					{
+						result.add(new UnknownSegment(marker, markerLength - 2,
+								is));
+
+						return result;
+					}
+					else
+					{
+						skipBytes(is, markerLength - 2,
+								"Not a Valid JPEG File: missing marker data");
+					}
+
+					if (debug)
+					{
+						System.out
+								.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+						System.out
+								.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+						System.out
+								.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+						System.out
+								.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+					}
+
+					if (return_after_first)
+						return result;
+				}
+				else
+				{
+					skipBytes(is, markerLength - 2,
+							"Not a Valid JPEG File: missing marker data");
+				}
+
+				if (marker == SOS_Marker)
+				{
+					//					Debug.debug("SOS");
+					return result;
+				}
+
+			}
+			if (debug)
+				System.out.println("");
+		}
+
+		return result;
+	}
+
+	public static final boolean permissive = true;
+
+	private byte[] assembleSegments(Vector v) throws ImageReadException,
+			IOException
+	{
+		try
+		{
+			return assembleSegments(v, false);
+		}
+		catch (ImageReadException e)
+		{
+			return assembleSegments(v, true);
+		}
+	}
+
+	private byte[] assembleSegments(Vector v, boolean start_with_zero)
+			throws ImageReadException, IOException
+	{
+		if (v.size() < 1)
+			throw new ImageReadException("No App2 Segments Found.");
+
+		int markerCount = ((App2Segment) v.get(0)).num_markers;
+
+		//		if (permissive && (markerCount == 0))
+		//			markerCount = v.size();
+
+		if (v.size() != markerCount)
+			throw new ImageReadException("App2 Segments Missing.  Found: "
+					+ v.size() + ", Expected: " + markerCount + ".");
+
+		Collections.sort(v);
+
+		int offset = start_with_zero ? 0 : 1;
+
+		int total = 0;
+		for (int i = 0; i < v.size(); i++)
+		{
+			App2Segment segment = (App2Segment) v.get(i);
+
+			if ((i + offset) != segment.cur_marker)
+			{
+				dumpSegments(v);
+				throw new ImageReadException(
+						"Incoherent App2 Segment Ordering.  i: " + i
+								+ ", segment[" + i + "].cur_marker: "
+								+ segment.cur_marker + ".");
+			}
+
+			if (markerCount != segment.num_markers)
+			{
+				dumpSegments(v);
+				throw new ImageReadException(
+						"Inconsistent App2 Segment Count info.  markerCount: "
+								+ markerCount + ", segment[" + i
+								+ "].num_markers: " + segment.num_markers + ".");
+			}
+
+			total += segment.icc_bytes.length;
+		}
+
+		byte result[] = new byte[total];
+		int progress = 0;
+
+		for (int i = 0; i < v.size(); i++)
+		{
+			App2Segment segment = (App2Segment) v.get(i);
+
+			System.arraycopy(segment.icc_bytes, 0, result, progress,
+					segment.icc_bytes.length);
+			progress += segment.icc_bytes.length;
+		}
+
+		return result;
+	}
+
+	private void dumpSegments(Vector v)
+	{
+		Debug.debug();
+		Debug.debug("dumpSegments", v.size());
+
+		for (int i = 0; i < v.size(); i++)
+		{
+			App2Segment segment = (App2Segment) v.get(i);
+
+			Debug.debug((i) + ": " + segment.cur_marker + " / "
+					+ segment.num_markers);
+		}
+		Debug.debug();
+	}
+
+	public Vector readSegments(ByteSource byteSource, int markers[],
+			boolean return_after_first) throws ImageReadException, IOException
+	{
+		return readSegments(byteSource, markers, return_after_first, false);
+	}
+
+	public Vector readSegments(ByteSource byteSource, int markers[],
+			boolean return_after_first, boolean readEverything)
+			throws ImageReadException, IOException
+	{
+		InputStream is = null;
+
+		try
+		{
+			is = byteSource.getInputStream();
+
+			readAndVerifyBytes(is, SOI,
+					"Not a Valid JPEG File: doesn't begin with 0xffd8");
+
+			return readMarkers(is, markers, return_after_first, readEverything);
+		}
+		finally
+		{
+			try
+			{
+				is.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+		}
+	}
+
+	public byte[] getICCProfileBytes(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		Vector segments = readSegments(byteSource, new int[]{
+			JPEG_APP2_Marker,
+		}, false);
+
+		if (segments != null)
+		{
+			// throw away non-icc profile app2 segments.
+			Vector filtered = new Vector();
+			for (int i = 0; i < segments.size(); i++)
+			{
+				App2Segment segment = (App2Segment) segments.get(i);
+				if (segment.icc_bytes != null)
+					filtered.add(segment);
+			}
+			segments = filtered;
+		}
+
+		if ((segments == null) || (segments.size() < 1))
+			return null;
+
+		byte bytes[] = assembleSegments(segments);
+
+		if (debug)
+			System.out.println("bytes" + ": "
+					+ ((bytes == null) ? null : "" + bytes.length));
+
+		if (debug)
+			System.out.println("");
+
+		return (bytes);
+	}
+
+	public IImageMetadata getMetadata(ByteSource byteSource, Map params)
+			throws ImageReadException, IOException
+	{
+		TiffImageMetadata exif = getExifMetadata(byteSource, params);
+
+		JpegImageMetadata.Photoshop photoshop = getPhotoshopMetadata(byteSource);
+
+		if (null == exif && null == photoshop)
+			return null;
+
+		JpegImageMetadata result = new JpegImageMetadata(photoshop, exif);
+
+		return result;
+	}
+
+	public static boolean isExifAPP1Segment(GenericSegment segment)
+	{
+		byte bytes[] = segment.bytes;
+
+		if ((bytes == null) || (bytes.length < 4))
+			return false;
+
+		for (int i = 0; i < 4 && i < bytes.length; i++)
+			if (bytes[i] != ExifIdentifierCode[i])
+				return false;
+
+		return true;
+	}
+
+	private Vector filterAPP1Segments(Vector v)
+	{
+		Vector result = new Vector();
+
+		for (int i = 0; i < v.size(); i++)
+		{
+			GenericSegment segment = (GenericSegment) v.get(i);
+			if (isExifAPP1Segment(segment))
+				result.add(segment);
+		}
+
+		return result;
+	}
+
+	public TiffImageMetadata getExifMetadata(ByteSource byteSource, Map params)
+			throws ImageReadException, IOException
+	{
+		byte bytes[] = getExifRawData(byteSource);
+		if (null == bytes)
+			return null;
+
+		return (TiffImageMetadata) new TiffImageParser().getMetadata(bytes,
+				params);
+	}
+
+	public byte[] getExifRawData(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		Vector segments = readSegments(byteSource, new int[]{
+			JPEG_APP1_Marker,
+		}, false);
+
+		if ((segments == null) || (segments.size() < 1))
+			return null;
+
+		Vector exifSegments = filterAPP1Segments(segments);
+		if (debug)
+			System.out.println("exif_segments.size" + ": "
+					+ exifSegments.size());
+
+		// TODO: concatenate if multiple segments, need example.
+		if (exifSegments.size() > 1)
+			throw new ImageReadException(
+					"Sanselan currently can't parse EXIF metadata split across multiple APP1 segments.  "
+							+ "Please send this image to the Sanselan project.");
+
+		GenericSegment segment = (GenericSegment) exifSegments.get(0);
+		byte bytes[] = segment.bytes;
+
+		//		byte head[] = readBytearray("exif head", bytes, 0, 6);
+		//
+		//		Debug.debug("head", head);
+
+		return getBytearrayTail("trimmed exif bytes", bytes, 6);
+	}
+
+	private JpegImageMetadata.Photoshop getPhotoshopMetadata(
+			ByteSource byteSource) throws ImageReadException, IOException
+	{
+		Vector segments = readSegments(byteSource, new int[]{
+			JPEG_APP13_Marker,
+		}, false);
+
+		if ((segments == null) || (segments.size() < 1))
+			return null;
+
+		JpegImageMetadata.Photoshop result = new JpegImageMetadata.Photoshop();
+
+		for (int i = 0; i < segments.size(); i++)
+		{
+			App13Segment segment = (App13Segment) segments.get(i);
+
+			Vector elements = segment.elements;
+
+			for (int j = 0; j < elements.size(); j++)
+			{
+				IptcElement element = (IptcElement) elements.get(j);
+				result.add(element.getIptcTypeName(), element.getValue());
+			}
+		}
+
+		return result;
+	}
+
+	public Dimension getImageSize(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		Vector segments = readSegments(byteSource, new int[]{
+				//			kJFIFMarker,
+				SOF0Marker,
+
+				SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker, SOF6Marker,
+				SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker, SOF13Marker,
+				SOF14Marker, SOF15Marker,
+
+		}, true);
+
+		if ((segments == null) || (segments.size() < 1))
+			throw new ImageReadException("No JFIF Data Found.");
+
+		if (segments.size() > 1)
+			throw new ImageReadException("Redundant JFIF Data Found.");
+
+		SOFNSegment fSOFNSegment = (SOFNSegment) segments.get(0);
+
+		return new Dimension(fSOFNSegment.width, fSOFNSegment.height);
+	}
+
+	public byte[] embedICCProfile(byte image[], byte profile[])
+	{
+		return null;
+	}
+
+	public boolean embedICCProfile(File src, File dst, byte profile[])
+	{
+		return false;
+	}
+
+	public ImageInfo getImageInfo(ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+
+		Vector SOF_segments = readSegments(byteSource, new int[]{
+				//				kJFIFMarker,
+
+				SOF0Marker, SOF1Marker, SOF2Marker, SOF3Marker, SOF5Marker,
+				SOF6Marker, SOF7Marker, SOF9Marker, SOF10Marker, SOF11Marker,
+				SOF13Marker, SOF14Marker, SOF15Marker,
+
+		}, false);
+
+		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());
+
+		Vector JFIF_segments = readSegments(byteSource, new int[]{
+			JFIFMarker,
+		}, true);
+
+		SOFNSegment fSOFNSegment = (SOFNSegment) SOF_segments.get(0);
+		//		SOFNSegment fSOFNSegment = (SOFNSegment) findSegment(segments, SOFNmarkers);
+
+		if (fSOFNSegment == null)
+			throw new ImageReadException("No SOFN Data Found.");
+
+		int Width = fSOFNSegment.width;
+		int Height = fSOFNSegment.height;
+
+		JFIFSegment fTheJFIFSegment = null;
+
+		if ((JFIF_segments != null) && (JFIF_segments.size() > 0))
+			fTheJFIFSegment = (JFIFSegment) JFIF_segments.get(0);
+
+		//		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;
+		String FormatDetails;
+
+		if (fTheJFIFSegment != null)
+		{
+			x_density = fTheJFIFSegment.xDensity;
+			y_density = fTheJFIFSegment.yDensity;
+			int density_units = fTheJFIFSegment.density_units;
+			//			JFIF_major_version = fTheJFIFSegment.JFIF_major_version;
+			//			JFIF_minor_version = fTheJFIFSegment.JFIF_minor_version;
+
+			FormatDetails = "Jpeg/JFIF v." + fTheJFIFSegment.JFIF_major_version
+					+ "." + fTheJFIFSegment.JFIF_minor_version;
+
+			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);
+
+			{
+				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_ResolutionUnit);
+				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));
+		}
+
+		Vector Comments = new Vector();
+		// TODO: comments...
+
+		int Number_of_components = fSOFNSegment.Number_of_components;
+		int Precision = fSOFNSegment.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 = fSOFNSegment.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;
+	}
+
+	public boolean dumpImageFile(PrintWriter pw, ByteSource byteSource)
+			throws ImageReadException, IOException
+	{
+		pw.println("tiff.dumpImageFile");
+
+		{
+			ImageInfo imageInfo = getImageInfo(byteSource);
+			if (imageInfo == null)
+				return false;
+
+			imageInfo.toString(pw, "");
+		}
+
+		pw.println("");
+
+		{
+			Vector segments = readSegments(byteSource, null, false);
+
+			if (segments == null)
+				throw new ImageReadException("No Segments Found.");
+
+			for (int d = 0; d < segments.size(); d++)
+			{
+
+				Segment segment = (Segment) segments.get(d);
+
+				NumberFormat nf = NumberFormat.getIntegerInstance();
+				//			this.debugNumber("found, marker: ", marker, 4);
+				pw.println(d + ": marker: "
+						+ Integer.toHexString(segment.marker) + ", "
+						+ segment.getDescription() + " (length: "
+						+ nf.format(segment.length) + ")");
+				segment.dump(pw);
+			}
+
+			pw.println("");
+		}
+
+		return true;
+	}
+
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,287 @@
+/*
+ * 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.exifRewrite;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.common.BinaryFileParser;
+import org.apache.sanselan.common.byteSources.ByteSource;
+import org.apache.sanselan.formats.jpeg.JpegConstants;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+import org.apache.sanselan.formats.jpeg.segments.GenericSegment;
+import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
+import org.apache.sanselan.formats.tiff.TagInfo;
+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.fieldtypes.FieldType;
+import org.apache.sanselan.formats.tiff.write.TiffImageWriter;
+import org.apache.sanselan.formats.tiff.write.WriteField;
+import org.apache.sanselan.util.Debug;
+
+public class ExifRewriter extends BinaryFileParser implements JpegConstants
+{
+	public ExifRewriter()
+	{
+		setByteOrder(BYTE_ORDER_NETWORK);
+	}
+
+	public void rewriteEXIFMetadata(ByteSource byteSource, OutputStream os,
+			Map params) throws ImageReadException, IOException,
+			ImageWriteException
+	{
+		Vector pieces = new Vector();
+		InputStream is = null;
+		GenericSegment exifSegment = null;
+
+		try
+		{
+			is = byteSource.getInputStream();
+
+			readAndVerifyBytes(is, SOI,
+					"Not a Valid JPEG File: doesn't begin with 0xffd8");
+
+			int byteOrder = getByteOrder();
+
+			for (int markerCount = 0; true; markerCount++)
+			{
+				byte markerBytes[] = readByteArray("markerBytes", 2, is,
+						"markerBytes");
+				int marker = convertByteArrayToShort("marker", markerBytes,
+						byteOrder);
+
+				//					private boolean isExifAPP1Segment(GenericSegment segment)
+
+				if (marker == 0xffd9 || marker == SOS_Marker)
+				{
+					pieces.add(markerBytes);
+					pieces.add(getStreamBytes(is));
+					break;
+				}
+
+				byte markerLengthBytes[] = readByteArray("markerLengthBytes",
+						2, is, "markerLengthBytes");
+				int markerLength = convertByteArrayToShort("markerLength",
+						markerLengthBytes, byteOrder);
+
+				UnknownSegment segment = new UnknownSegment(marker,
+						markerLength - 2, is);
+
+				if (marker != JPEG_APP1_Marker)
+				{
+					pieces.add(markerBytes);
+					pieces.add(markerLengthBytes);
+					pieces.add(segment.bytes);
+					continue;
+				}
+
+				if (!JpegImageParser.isExifAPP1Segment(segment))
+				{
+					pieces.add(markerBytes);
+					pieces.add(markerLengthBytes);
+					pieces.add(segment.bytes);
+					continue;
+				}
+
+				if (exifSegment != null)
+				{
+					// TODO: add support for multiple segments
+					throw new ImageWriteException(
+							"More than one APP1 EXIF segment.");
+				}
+
+				exifSegment = segment;
+				pieces.add(segment);
+			}
+
+		}
+		finally
+		{
+			try
+			{
+				is.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+		}
+
+		if (exifSegment == null)
+		{
+			// TODO: add support for adding, not just replacing.
+			throw new ImageWriteException("No APP1 EXIF segment found.");
+		}
+
+		byte exifBytes[] = exifSegment.bytes;
+		exifBytes = getBytearrayTail("trimmed exif bytes", exifBytes, 6);
+
+		TiffImageMetadata exifMetadata = (TiffImageMetadata) new TiffImageParser()
+				.getMetadata(exifBytes, params);
+
+		byte newBytes[] = rewriteExif(exifMetadata, true);
+		//		exifSegment.bytes = newBytes;
+
+		//		Vector segments = readSegments(byteSource, null, false, true);
+
+		//		TiffImageMetadata exif = getExifMetadata(byteSource, params);
+
+		writeSegments(os, pieces, newBytes);
+	}
+
+	private void writeSegments(OutputStream os, Vector segments,
+			byte newBytes[]) throws ImageWriteException, IOException
+	{
+		int byteOrder = getByteOrder();
+
+		try
+		{
+			os.write(SOI);
+
+			for (int i = 0; i < segments.size(); i++)
+			{
+				Object o = segments.get(i);
+				if (o instanceof byte[])
+				{
+					byte bytes[] = (byte[]) o;
+					os.write(bytes);
+				}
+				else if (o instanceof GenericSegment)
+				{
+					//					byte markerBytes[] = readByteArray("markerBytes", 2, is,
+					//					"markerBytes");
+					//			int marker = convertByteArrayToShort("marker", markerBytes,
+					//					byteOrder);
+					byte markerBytes[] = convertShortToByteArray(
+							JPEG_APP1_Marker, byteOrder);
+					os.write(markerBytes);
+
+					int markerLength = newBytes.length + 2;
+					byte markerLengthBytes[] = convertShortToByteArray(
+							markerLength, byteOrder);
+					os.write(markerLengthBytes);
+
+					//
+					//			pieces.add(markerBytes);
+					//					pieces.add(markerLengthBytes);
+
+					os.write(newBytes);
+					//					GenericSegment segment = (GenericSegment) o;
+					//					os.write(segment.bytes);
+				}
+				else
+					throw new ImageWriteException("Unknown data: " + o);
+			}
+			//			readAndVerifyBytes(is, SOI,
+			//					"Not a Valid JPEG File: doesn't begin with 0xffd8");
+			//
+			//			return readMarkers(is, markers, return_after_first);
+		}
+		finally
+		{
+			try
+			{
+				os.close();
+			}
+			catch (Exception e)
+			{
+				Debug.debug(e);
+			}
+		}
+	}
+
+	public byte[] rewriteExif(TiffImageMetadata exif, boolean includeEXIFPrefix)
+			throws IOException, ImageWriteException
+	{
+		if (exif == null)
+			return null;
+
+		int byteOrder = exif.contents.header.byteOrder;
+
+		Vector dstDirs = new Vector();
+		Vector srcDirs = exif.getDirectories();
+		for (int i = 0; i < srcDirs.size(); i++)
+		{
+			TiffImageMetadata.Directory srcDir = (TiffImageMetadata.Directory) srcDirs
+					.get(i);
+			//			Debug.debug("srcDir", srcDir);
+
+			TiffImageWriter.Directory dstDir = translate(srcDir, byteOrder);
+			dstDirs.add(dstDir);
+		}
+
+		ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+		if (includeEXIFPrefix)
+		{
+			os.write(ExifIdentifierCode);
+			os.write(0);
+			os.write(0);
+		}
+
+		new TiffImageWriter(byteOrder).writeDirectories(os, dstDirs);
+
+		return os.toByteArray();
+	}
+
+	private TiffImageWriter.Directory translate(
+			TiffImageMetadata.Directory srcDir, int byteOrder)
+			throws ImageWriteException
+	{
+		TiffImageWriter.Directory dstDir = new TiffImageWriter.Directory(
+				srcDir.type);
+
+		Vector entries = srcDir.getItems();
+		for (int i = 0; i < entries.size(); i++)
+		{
+			TiffImageMetadata.Item item = (TiffImageMetadata.Item) entries
+					.get(i);
+			TiffField srcField = item.getTiffField();
+
+			TagInfo tag = srcField.tagInfo;
+			FieldType tagtype = srcField.fieldType;
+			int count = srcField.length;
+			byte bytes[] = srcField.fieldType.getRawBytes(srcField);
+
+			//			Debug.debug("\t" + "srcField", srcField);
+			//			Debug.debug("\t" + "bytes", bytes);
+
+			Object value = srcField.getValue();
+			byte bytes2[];
+			if (tag.isDate)
+				bytes2 = tagtype.getRawBytes(srcField);
+			else
+				bytes2 = tagtype.writeData(value, byteOrder);
+			//			Debug.debug("\t" + "bytes2", bytes2);
+
+			WriteField dstField = new WriteField(tag, tagtype, count, bytes2);
+			dstDir.add(dstField);
+		}
+
+		dstDir.setRawTiffImageData(srcDir.getRawTiffImageData());
+		dstDir.setRawJpegImageData(srcDir.getRawJpegImageData());
+
+		return dstDir;
+	}
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/APPNSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,38 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class APPNSegment extends GenericSegment
+{
+	public APPNSegment(int marker, int marker_length, InputStream is)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length, is);
+	}
+
+	public String getDescription()
+	{
+		return "APPN (APP" + (marker - JpegImageParser.JPEG_APP0_Marker)
+				+ ") (" + getSegmentType() + ")";
+	}
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App13Segment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,143 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.IptcElement;
+import org.apache.sanselan.formats.jpeg.IptcType;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class App13Segment extends APPNSegment
+{
+	protected final JpegImageParser parser;
+	public final Vector elements = new Vector();
+
+	public App13Segment(JpegImageParser parser, int marker, int marker_length,
+			InputStream is2) throws ImageReadException, IOException
+	{
+		super(marker, marker_length, is2);
+		this.parser = parser;
+
+		//			InputStream bais = new ByteArrayInputStream(bytes);
+		//			dump();
+
+		//		Debug.debug("bytes", bytes);
+		boolean verbose = false;
+
+		if (!compareByteArrays(bytes, 0,
+				JpegImageParser.PhotoshopIdentificationString, 0,
+				JpegImageParser.PhotoshopIdentificationString.length))
+			throw new ImageReadException("Invalid App13 Segment");
+		//			readAndVerifyBytes("Photoshop Identification String", bais,
+		//					kPhotoshopIdentificationString, "Invalid App13 Segment");
+
+		int index = JpegImageParser.PhotoshopIdentificationString.length;
+		while (index < bytes.length)
+		{
+			if (!compareByteArrays(bytes, index, JpegImageParser.CONST_8BIM, 0,
+					JpegImageParser.CONST_8BIM.length))
+			{
+				//					dump(index);
+				throw new ImageReadException("Invalid .CONST_8BIM Segment");
+			}
+			index += JpegImageParser.CONST_8BIM.length;
+
+			int segmentType = convertByteArrayToShort("SegmentType", index,
+					bytes);
+			if (verbose)
+				debugNumber("SegmentType", segmentType, 2);
+			index += 2;
+
+			// padding
+			index += 4;
+
+			int segmentSize = convertByteArrayToShort("SegmentSize", index,
+					bytes);
+			if (verbose)
+				debugNumber("fSegmentSize", segmentSize, 2);
+			index += 2;
+
+			int index2 = index;
+
+			index += segmentSize;
+			if ((segmentSize % 2) != 0)
+				index++;
+
+			while (index2 < index)
+			{
+				int iptcPrefix = convertByteArrayToShort("IPTCPrefix", index2,
+						bytes);
+				if (verbose)
+					debugNumber("fIPTCPrefix", iptcPrefix, 2);
+				index2 += 2;
+
+				if (iptcPrefix == 0x1c02)
+				{
+					//						System.out.println("								TEXTBLOCK:  "
+					//								+ fSegmentType);
+				}
+				else
+				{
+					//						System.out.println("								!TEXTBLOCK: " + fSegmentType);
+					break;
+				}
+
+				byte iptcSegmentType = bytes[index2];
+				//					debugNumber("fIPTCSegmentType", fIPTCSegmentType);
+				index2++;
+
+				int iptcSegmentSize = convertByteArrayToShort(
+						"IPTCSegmentSize", index2, bytes);
+				//					debugNumber("fIPTCegmentSize", fIPTCegmentSize, 2);
+				index2 += 2;
+
+				byte iptcData[] = readBytearray("iptc_data", bytes, index2,
+						iptcSegmentSize);
+				index2 += iptcSegmentSize;
+
+				String value = new String(iptcData);
+				//					System.out.println("iptc_data: '" + value + "' ("
+				//							+ fIPTCegmentSize + ")");
+
+				IptcType iptcType = IptcType.getIptcType(iptcSegmentType);
+				IptcElement element = new IptcElement(iptcType, value);
+				elements.add(element);
+			}
+
+		}
+		//			System.out.println("								zimbabwe legit");
+
+		//
+		//			{
+		//				int i = read_byte("zero", is, "Invalid App13 Segment");
+		//				if (i != 0)
+		//					throw new ImageReadException("Invalid App13 Segment");
+		//			}
+
+		//			while (true)
+		//			{
+		//				readAndVerifyBytes(.CONST_8BIM", bais, .CONST_8BIM, "Invalid.CONST_8BIM Segment");
+		//				System.out.println();
+		//			}
+
+	}
+
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/App2Segment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,73 @@
+/*
+ * 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.segments;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class App2Segment extends APPNSegment implements Comparable
+{
+	public final byte icc_bytes[];
+	public final int cur_marker, num_markers;
+
+	public App2Segment(int marker, int marker_length, InputStream is2)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length, is2);
+
+		if (startsWith(bytes, JpegImageParser.icc_profile_label))
+		{
+			InputStream is = new ByteArrayInputStream(bytes);
+
+			readAndVerifyBytes(is, JpegImageParser.icc_profile_label,
+					"Not a Valid App2 Segment: missing ICC Profile label");
+
+			cur_marker = readByte("cur_marker", is, "Not a valid App2 Marker");
+			num_markers = readByte("num_markers", is, "Not a valid App2 Marker");
+
+			marker_length -= JpegImageParser.icc_profile_label.length;
+			marker_length -= (1 + 1);
+
+			icc_bytes = readByteArray("App2 Data", marker_length, is,
+					"Invalid App2 Segment: insufficient data");
+		}
+		else
+		{
+			debugByteArray("Unknown APP2 Segment Type", bytes);
+			cur_marker = -1;
+			num_markers = -1;
+			icc_bytes = null;
+		}
+	}
+
+	public int compareTo(Object o)
+	{
+		App2Segment other = (App2Segment) o;
+		return cur_marker - other.cur_marker;
+	}
+
+	//	public String getDescription()
+	//	{
+	//		return "APPN (APP"
+	//				+ (marker - JpegImageParser.JPEG_APP0)
+	//				+ ") (" + getDescription() + ")";
+	//	}
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/GenericSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,55 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+
+import org.apache.sanselan.ImageReadException;
+
+public abstract class GenericSegment extends Segment
+{
+	public final byte bytes[];
+
+	public GenericSegment(int marker, int marker_length, InputStream is)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length);
+
+		bytes = readByteArray("Segment Data", marker_length, is,
+				"Invalid Segment: insufficient data");
+	}
+
+	public void dump(PrintWriter pw)
+	{
+		dump(pw, 0);
+	}
+
+	public void dump(PrintWriter pw, int start)
+	{
+		for (int i = 0; (i < 50) && ((i + start) < bytes.length); i++)
+		{
+			debugNumber(pw, "\t" + (i + start), bytes[i + start]);
+		}
+	}
+
+	//	public String getDescription()
+	//	{
+	//		return "Unknown";
+	//	}
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/JFIFSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,78 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+
+public class JFIFSegment extends Segment
+{
+	public final int JFIF_major_version;
+	public final int JFIF_minor_version;
+	public final int density_units;
+	public final int xDensity;
+	public final int yDensity;
+
+	public final int xThumbnail;
+	public final int yThumbnail;
+	public final int thumbnailSize;
+
+	public String getDescription()
+	{
+		return "JFIF (" + getSegmentType() + ")";
+	}
+
+	private static final byte JFIF0_SIGNATURE[] = new byte[]{
+			(byte) 'J', (byte) 'F', (byte) 'I', (byte) 'F', (byte) 0,
+	};
+
+	public JFIFSegment(int marker, int marker_length, InputStream is)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length);
+
+		{
+			readAndVerifyBytes(is, JFIF0_SIGNATURE,
+					"Not a Valid JPEG File: missing JFIF string");
+
+			JFIF_major_version = readByte("JFIF_major_version", is,
+					"Not a Valid JPEG File");
+			JFIF_minor_version = readByte("JFIF_minor_version", is,
+					"Not a Valid JPEG File");
+			density_units = readByte("density_units", is,
+					"Not a Valid JPEG File");
+			xDensity = read2Bytes("x_density", is, "Not a Valid JPEG File");
+			yDensity = read2Bytes("y_density", is, "Not a Valid JPEG File");
+
+			xThumbnail = readByte("x_thumbnail", is, "Not a Valid JPEG File");
+			yThumbnail = readByte("y_thumbnail", is, "Not a Valid JPEG File");
+			thumbnailSize = xThumbnail * yThumbnail;
+			if (thumbnailSize > 0)
+			{
+				skipBytes(is, thumbnailSize,
+						"Not a Valid JPEG File: missing thumbnail");
+
+			}
+		}
+
+		if (getDebug())
+			System.out.println("");
+	}
+
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOFNSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,71 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.formats.jpeg.JpegImageParser;
+
+public class SOFNSegment extends Segment
+{
+	public final int width, height;
+	public final int Number_of_components;
+	public final int Precision;
+
+	//		public final byte bytes[];
+	//		public final int cur_marker, num_markers;
+
+	public SOFNSegment(int marker, int marker_length, InputStream is)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length);
+
+		if (getDebug())
+			System.out.println("SOF0Segment marker_length: " + marker_length);
+
+		{
+			Precision = readByte("Data_precision", is, "Not a Valid JPEG File");
+			height = read2Bytes("Image_height", is, "Not a Valid JPEG File");
+			width = read2Bytes("Image_Width", is, "Not a Valid JPEG File");
+			Number_of_components = readByte("Number_of_components", is,
+					"Not a Valid JPEG File");
+
+			// ignore the rest of the segment for now...
+			skipBytes(is, marker_length - 6,
+					"Not a Valid JPEG File: SOF0 Segment");
+
+			//				int Each_component1 = read_byte("Each_component1", is,
+			//						"Not a Valid JPEG File");
+			//				int Each_component2 = read_byte("Each_component2", is,
+			//						"Not a Valid JPEG File");
+			//				int Each_component3 = read_byte("Each_component3", is,
+			//						"Not a Valid JPEG File");
+		}
+
+		if (getDebug())
+			System.out.println("");
+	}
+
+	public String getDescription()
+	{
+		return "SOFN (SOF" + (marker - JpegImageParser.SOF0Marker) + ") ("
+				+ getSegmentType() + ")";
+	}
+
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/SOSSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,100 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+import org.apache.sanselan.util.Debug;
+
+public class SOSSegment extends Segment
+{
+	//	public final int width, height;
+	//	public final int Number_of_components;
+	//	public final int Precision;
+
+	//		public final byte bytes[];
+	//		public final int cur_marker, num_markers;
+
+	public SOSSegment(int marker, int marker_length, InputStream is)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length);
+
+		if (getDebug())
+			System.out.println("SOSSegment marker_length: " + marker_length);
+
+		Debug.debug("SOS", marker_length);
+		//		{
+		int number_of_components_in_scan = readByte(
+				"number_of_components_in_scan", is, "Not a Valid JPEG File");
+		Debug.debug("number_of_components_in_scan",
+				number_of_components_in_scan);
+
+		for (int i = 0; i < number_of_components_in_scan; i++)
+		{
+			int scan_component_selector = readByte("scan_component_selector",
+					is, "Not a Valid JPEG File");
+			Debug.debug("scan_component_selector", scan_component_selector);
+
+			int ac_dc_entrooy_coding_table_selector = readByte(
+					"ac_dc_entrooy_coding_table_selector", is,
+					"Not a Valid JPEG File");
+			Debug.debug("ac_dc_entrooy_coding_table_selector",
+					ac_dc_entrooy_coding_table_selector);
+		}
+
+		int start_of_spectral_selection = readByte(
+				"start_of_spectral_selection", is, "Not a Valid JPEG File");
+		Debug.debug("start_of_spectral_selection", start_of_spectral_selection);
+		int end_of_spectral_selection = readByte("end_of_spectral_selection",
+				is, "Not a Valid JPEG File");
+		Debug.debug("end_of_spectral_selection", end_of_spectral_selection);
+		int successive_approximation_bit_position = readByte(
+				"successive_approximation_bit_position", is,
+				"Not a Valid JPEG File");
+		Debug.debug("successive_approximation_bit_position",
+				successive_approximation_bit_position);
+
+		//			height = read2Bytes("Image_height", is, "Not a Valid JPEG File");
+		//			width = read2Bytes("Image_Width", is, "Not a Valid JPEG File");
+		//			Number_of_components = read_byte("Number_of_components", is,
+		//					"Not a Valid JPEG File");
+		//
+		//			// ignore the rest of the segment for now...
+		//			skipBytes(is, marker_length - 6,
+		//					"Not a Valid JPEG File: SOF0 Segment");
+		//
+		//			//				int Each_component1 = read_byte("Each_component1", is,
+		//			//						"Not a Valid JPEG File");
+		//			//				int Each_component2 = read_byte("Each_component2", is,
+		//			//						"Not a Valid JPEG File");
+		//			//				int Each_component3 = read_byte("Each_component3", is,
+		//			//						"Not a Valid JPEG File");
+		//		}
+
+		if (getDebug())
+			System.out.println("");
+	}
+
+	public String getDescription()
+	{
+		return "SOS (" + getSegmentType() + ")";
+	}
+
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/Segment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,142 @@
+/*
+ * 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.segments;
+
+import java.io.PrintWriter;
+
+import org.apache.sanselan.common.BinaryFileParser;
+
+public abstract class Segment extends BinaryFileParser
+{
+	public final int marker;
+	public final int length;
+
+	public Segment(int marker, int length)
+	{
+		//		super();
+
+		this.marker = marker;
+		this.length = length;
+	}
+
+	public void dump(PrintWriter pw)
+	{
+	}
+
+	public abstract String getDescription();
+
+	public String getSegmentType()
+	{
+
+		switch (marker)
+		{
+			case 0xffc0 :
+				return "Start Of Frame, Baseline DCT, Huffman coding";
+			case 0xffc1 :
+				return "Start Of Frame, Extended sequential DCT, Huffman coding";
+			case 0xffc2 :
+				return "Start Of Frame, Progressive DCT, Huffman coding";
+			case 0xffc3 :
+				return "Start Of Frame, Lossless (sequential), Huffman coding";
+
+			case 0xffc5 :
+				return "Start Of Frame, Differential sequential DCT, Huffman coding";
+			case 0xffc6 :
+				return "Start Of Frame, Differential progressive DCT, Huffman coding";
+			case 0xffc7 :
+				return "Start Of Frame, Differential lossless (sequential), Huffman coding";
+
+			case 0xffc8 :
+				return "Start Of Frame, Reserved for JPEG extensions, arithmetic coding";
+			case 0xffc9 :
+				return "Start Of Frame, Extended sequential DCT, arithmetic coding";
+			case 0xffca :
+				return "Start Of Frame, Progressive DCT, arithmetic coding";
+			case 0xffcb :
+				return "Start Of Frame, Lossless (sequential), arithmetic coding";
+
+			case 0xffcd :
+				return "Start Of Frame, Differential sequential DCT, arithmetic coding";
+			case 0xffce :
+				return "Start Of Frame, Differential progressive DCT, arithmetic coding";
+			case 0xffcf :
+				return "Start Of Frame, Differential lossless (sequential), arithmetic coding";
+
+			case 0xffc4 :
+				return "Define Huffman table(s)";
+			case 0xffcc :
+				return "Define arithmetic coding conditioning(s)";
+
+			case 0xffd0 :
+				return "Restart with modulo 8 count 0";
+			case 0xffd1 :
+				return "Restart with modulo 8 count 1";
+			case 0xffd2 :
+				return "Restart with modulo 8 count 2";
+			case 0xffd3 :
+				return "Restart with modulo 8 count 3";
+			case 0xffd4 :
+				return "Restart with modulo 8 count 4";
+			case 0xffd5 :
+				return "Restart with modulo 8 count 5";
+			case 0xffd6 :
+				return "Restart with modulo 8 count 6";
+			case 0xffd7 :
+				return "Restart with modulo 8 count 7";
+
+			case 0xffd8 :
+				return "Start of image";
+			case 0xffd9 :
+				return "End of image";
+			case 0xffda :
+				return "Start of scan";
+			case 0xffdb :
+				return "Define quantization table(s)";
+			case 0xffdc :
+				return "Define number of lines";
+			case 0xffdd :
+				return "Define restart interval";
+			case 0xffde :
+				return "Define hierarchical progression";
+			case 0xffdf :
+				return "Expand reference component(s)";
+				//			case 0xffd8 :
+				//				return "Reserved for application segments";
+				//			case 0xffd8 :
+				//				return "Reserved for JPEG extensions";
+			case 0xfffe :
+				return "Comment";
+			case 0xff01 :
+				return "For temporary private use in arithmetic coding";
+				//			case 0xffd8 :
+				//				return "Reserved";
+
+			default :
+		}
+
+		if ((marker >= 0xff02) && (marker <= 0xffbf))
+			return "Reserved";
+		if ((marker >= 0xffe0) && (marker <= 0xffef))
+			return "APP" + (marker - 0xffe0);
+		if ((marker >= 0xfff0) && (marker <= 0xfffd))
+			return "JPG" + (marker - 0xffe0);
+
+		return "Unknown";
+
+	}
+
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/segments/UnknownSegment.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,36 @@
+/*
+ * 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.segments;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.sanselan.ImageReadException;
+
+public class UnknownSegment extends GenericSegment
+{
+	public UnknownSegment(int marker, int marker_length, InputStream is)
+			throws ImageReadException, IOException
+	{
+		super(marker, marker_length, is);
+	}
+
+	public String getDescription()
+	{
+		return "Unknown (" + getSegmentType() + ")";
+	}
+}
\ No newline at end of file

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

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,88 @@
+/*
+ * 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.png;
+
+import java.io.IOException;
+
+import org.apache.sanselan.ImageReadException;
+
+public class BitParser
+{
+	private final byte bytes[];
+	private final int BitsPerPixel;
+	private final int BitDepth;
+
+	public BitParser(byte bytes[], int BitsPerPixel, int BitDepth)
+	{
+		this.bytes = bytes;
+		this.BitsPerPixel = BitsPerPixel;
+		this.BitDepth = BitDepth;
+	}
+
+	public int getSample(int pixel_index_in_scanline, int SampleIndex)
+			throws ImageReadException, IOException
+	{
+		int pixel_index_bits = BitsPerPixel * pixel_index_in_scanline;
+		int sample_index_bits = pixel_index_bits + (SampleIndex * BitDepth);
+		//		int sample_index_bytes = sample_index_bits / 8;
+		int sample_index_bytes = sample_index_bits >> 3;
+		//		int sample_index_bytes = pixel_index_bits / 8;
+
+		//		System.out.println("sample_index_bytes: " + sample_index_bytes);
+
+		if (BitDepth == 8)
+			return 0xff & bytes[sample_index_bytes];
+		else if (BitDepth < 8)
+		{
+			int b = 0xff & bytes[sample_index_bytes];
+			//			int bits_to_shift = 8 - ((pixel_index_bits % 8) + BitsPerPixel);
+			int bits_to_shift = 8 - ((pixel_index_bits & 7) + BitDepth);
+			//			int bits_to_shift = 8 - ((pixel_index_bits % 8) + BitDepth);
+			b >>= bits_to_shift;
+
+			int bitmask = (1 << BitDepth) - 1;
+			return b & bitmask;
+			//			switch (BitDepth)
+			//			{
+			//				case 1 :
+			//					return b & 1;
+			//				case 2 :
+			//					return b & 3;
+			//				case 4 :
+			//					return b & 15;
+			//			}
+		}
+		else if (BitDepth == 16)
+		{
+			return ((0xff & (bytes[sample_index_bytes] << 8)) | (0xff & bytes[sample_index_bytes + 1]));
+		}
+
+		throw new ImageReadException("PNG: bad BitDepth: " + BitDepth);
+	}
+
+	public int getSampleAsByte(int pixel_index_in_scanline, int SampleIndex)
+			throws ImageReadException, IOException
+	{
+		int sample = getSample(pixel_index_in_scanline, SampleIndex);
+		int rot = 8 - BitDepth;
+		if (rot > 0)
+			sample <<= rot;
+		else if (rot < 0)
+			sample >>= -rot;
+		return 0xff & sample;
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/BitParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,74 @@
+/*
+ * 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.png;
+
+public class GammaCorrection
+{
+	//		private final double src_gamma, dst_gamma;
+	private final int lookup_table[];
+
+	public GammaCorrection(double src_gamma, double dst_gamma)
+	{
+		//			this.src_gamma = src_gamma;
+		//			this.dst_gamma = dst_gamma;
+		System.out.println("src_gamma: " + src_gamma);
+		System.out.println("dst_gamma: " + dst_gamma);
+
+		lookup_table = new int[256];
+		for (int i = 0; i < 256; i++)
+		{
+			lookup_table[i] = correctSample(i, src_gamma, dst_gamma);
+			System.out.println("lookup_table[" + i + "]: " + lookup_table[i]);
+		}
+	}
+
+	public int correctSample(int sample)
+	{
+		return lookup_table[sample];
+	}
+
+	public int correctARGB(int pixel)
+	{
+		int alpha = (0xff000000) & pixel;
+		int red = (pixel & 0xff) >> 16;
+		int green = (pixel & 0xff) >> 8;
+		int blue = (pixel & 0xff) >> 0;
+
+		red = correctSample(red);
+		green = correctSample(green);
+		blue = correctSample(blue);
+
+		int rgb = alpha | ((0xff & red) << 16) | ((0xff & green) << 8)
+				| ((0xff & blue) << 0);
+
+		return rgb;
+	}
+
+	private int correctSample(int sample, double src_gamma, double dst_gamma)
+	{
+		//			if (kUseAdobeGammaMethod && val <= 32)
+		//			{
+		//				double slope = Math.round(255.0d * Math.pow((32.0 / 255.0d),
+		//						src_gamma / dst_gamma)) / 32.d;
+		//				return (int) (sample * slope);
+		//			}
+
+		return (int) Math.round(255.0d * Math.pow((sample / 255.0d), src_gamma
+				/ dst_gamma));
+	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/GammaCorrection.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,104 @@
+/*
+ * 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.png;
+
+import org.apache.sanselan.SanselanConstants;
+
+public interface PngConstants extends SanselanConstants
+{
+
+	public static final int COMPRESSION_DEFLATE_INFLATE = 0;
+
+	public final static byte[] IHDR_CHUNK_TYPE = new byte[]{
+			73, 72, 68, 82
+	};
+	public final static byte[] PLTE_CHUNK_TYPE = new byte[]{
+			80, 76, 84, 69
+	};
+	public final static byte[] IEND_CHUNK_TYPE = new byte[]{
+			73, 69, 78, 68
+	};
+	public final static byte[] IDAT_CHUNK_TYPE = new byte[]{
+			73, 68, 65, 84
+	};
+
+	public final static int IEND = PngImageParser.CharsToQuad('I', 'E', 'N',
+			'D');
+	public final static int IHDR = PngImageParser.CharsToQuad('I', 'H', 'D',
+			'R');
+	public final static int iCCP = PngImageParser.CharsToQuad('i', 'C', 'C',
+			'P');
+	public final static int tEXt = PngImageParser.CharsToQuad('t', 'E', 'X',
+			't');
+	public final static int zTXt = PngImageParser.CharsToQuad('z', 'T', 'X',
+			't');
+	public final static int pHYs = PngImageParser.CharsToQuad('p', 'H', 'Y',
+			's');
+	public final static int PLTE = PngImageParser.CharsToQuad('P', 'L', 'T',
+			'E');
+	public final static int IDAT = PngImageParser.CharsToQuad('I', 'D', 'A',
+			'T');
+	public final static int tRNS = PngImageParser.CharsToQuad('t', 'R', 'N',
+			'S');
+	public final static int gAMA = PngImageParser.CharsToQuad('g', 'A', 'M',
+			'A');
+	public final static int sRGB = PngImageParser.CharsToQuad('s', 'R', 'G',
+			'B');
+
+	public static final byte PNG_Signature[] = {
+			(byte) 137, 80, 78, 71, 13, 10, 26, 10,
+	};
+
+	public static final String PARAM_KEY_PNG_BIT_DEPTH = "PNG_BIT_DEPTH";
+	public static final String PARAM_KEY_PNG_FORCE_INDEXED_COLOR = "PNG_FORCE_INDEXED_COLOR";
+	public static final String PARAM_KEY_PNG_FORCE_TRUE_COLOR = "PNG_FORCE_TRUE_COLOR";
+
+	//	public static final Object PARAM_KEY_PNG_BIT_DEPTH_YES = "YES";
+	//	public static final Object PARAM_KEY_PNG_BIT_DEPTH_NO = "NO";
+
+	public static final int COLOR_TYPE_GREYSCALE = 0;
+	public static final int COLOR_TYPE_TRUE_COLOR = 2;
+	public static final int COLOR_TYPE_INDEXED_COLOR = 3;
+	public static final int COLOR_TYPE_GREYSCALE_WITH_ALPHA = 4;
+	public static final int COLOR_TYPE_TRUE_COLOR_WITH_ALPHA = 6;
+
+	public static final byte COMPRESSION_TYPE_INFLATE_DEFLATE = 0;
+	public static final byte FILTER_METHOD_ADAPTIVE = 0;
+
+	public static final byte INTERLACE_METHOD_NONE = 0;
+	public static final byte INTERLACE_METHOD_ADAM7 = 1;
+
+	public static final byte FILTER_TYPE_NONE = 0;
+	public static final byte FILTER_TYPE_SUB = 1;
+	public static final byte FILTER_TYPE_UP = 2;
+	public static final byte FILTER_TYPE_AVERAGE = 3;
+	public static final byte FILTER_TYPE_PAETH = 4;
+
+	/*
+	 Background colour 	Solid background colour to be used when presenting the image if no better option is available.
+	 Gamma and chromaticity 	Gamma characteristic of the image with respect to the desired output intensity, and chromaticity characteristics of the RGB values used in the image.
+	 ICC profile 	Description of the colour space (in the form of an International Color Consortium (ICC) profile) to which the samples in the image conform.
+	 Image histogram 	Estimates of how frequently the image uses each palette entry.
+	 Physical pixel dimensions 	Intended pixel size and aspect ratio to be used in presenting the PNG image.
+	 Significant bits 	The number of bits that are significant in the samples.
+	 sRGB colour space 	A rendering intent (as defined by the International Color Consortium) and an indication that the image samples conform to this colour space.
+	 Suggested palette 	A reduced palette that may be used when the display device is not capable of displaying the full range of colours in the image.
+	 Textual data 	Textual information (which may be compressed) associated with the image.
+	 Time 	The time when the PNG image was last modified.
+	 Transparency 	Alpha information that allows the reference image to be reconstructed when the alpha channel is not retained in the PNG image.
+	 */
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java?rev=599250&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java Wed Nov 28 18:27:05 2007
@@ -0,0 +1,91 @@
+/*
+ * 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.png;
+
+// should just use ints, not longs
+public class PngCrc
+{
+	/* Table of CRCs of all 8-bit messages. */
+	private final long crc_table[] = new long[256];
+
+	/* Flag: has the table been computed? Initially false. */
+	private boolean crc_table_computed = false;
+
+	/* Make the table for a fast CRC. */
+	private void make_crc_table()
+	{
+		long c;
+		int n, k;
+
+		for (n = 0; n < 256; n++)
+		{
+			c = n;
+			for (k = 0; k < 8; k++)
+			{
+				if ((c & 1) != 0)
+
+					c = 0xedb88320L ^ (c >> 1);
+				else
+					c = c >> 1;
+			}
+			crc_table[n] = c;
+		}
+		crc_table_computed = true;
+	}
+
+	/* Update a running CRC with the bytes buf[0..len-1]--the CRC
+	 should be initialized to all 1's, and the transmitted value
+	 is the 1's complement of the final running CRC (see the
+	 crc() routine below)). */
+
+	private final long update_crc(long crc, byte buf[])
+	{
+		long c = crc;
+		int n;
+
+		if (!crc_table_computed)
+			make_crc_table();
+		for (n = 0; n < buf.length; n++)
+		{
+			//			Debug.debug("crc[" + n + "]", c + " (" + Long.toHexString(c) + ")");
+
+			c = crc_table[(int) ((c ^ buf[n]) & 0xff)] ^ (c >> 8);
+		}
+		return c;
+	}
+
+	/* Return the CRC of the bytes buf[0..len-1]. */
+	public final int crc(byte buf[], int len)
+	{
+		return (int) (update_crc(0xffffffffL, buf) ^ 0xffffffffL);
+	}
+
+	public final long start_partial_crc(byte buf[], int len)
+	{
+		return update_crc(0xffffffffL, buf);
+	}
+
+	public final long continue_partial_crc(long old_crc, byte buf[], int len)
+	{
+		return update_crc(old_crc, buf);
+	}
+
+	public final long finish_partial_crc(long old_crc)
+	{
+		return (old_crc ^ 0xffffffffL);
+	}
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/png/PngCrc.java
------------------------------------------------------------------------------
    svn:eol-style = native