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/01/07 04:39:12 UTC

svn commit: r609512 - in /incubator/sanselan/trunk/src: main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ main/java/org/apache/sanselan/formats/tiff/ main/java/org/apache/sanselan/formats/tiff/write/ test/java/org/apache/sanselan/formats/jpeg/

Author: cmchen
Date: Sun Jan  6 20:39:11 2008
New Revision: 609512

URL: http://svn.apache.org/viewvc?rev=609512&view=rev
Log:
refactor in preparation of starting work on lossless/cautious exif rewrite.

Added:
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java   (with props)
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossy.java   (with props)
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputSummary.java   (with props)
Removed:
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/PointerDirectoriesInfo.java
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriter.java
Modified:
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/TiffImageParser.java
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java
    incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputDirectory.java
    incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/ExifRewriteTest.java

Modified: 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=609512&r1=609511&r2=609512&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/jpeg/exifRewrite/ExifRewriter.java Sun Jan  6 20:39:11 2008
@@ -33,7 +33,9 @@
 import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
 import org.apache.sanselan.formats.tiff.TiffImageMetadata;
 import org.apache.sanselan.formats.tiff.TiffImageParser;
-import org.apache.sanselan.formats.tiff.write.TiffImageWriter;
+import org.apache.sanselan.formats.tiff.write.TiffImageWriterLossy;
+import org.apache.sanselan.formats.tiff.write.TiffImageWriterBase;
+import org.apache.sanselan.formats.tiff.write.TiffImageWriterLossless;
 import org.apache.sanselan.formats.tiff.write.TiffOutputDirectory;
 import org.apache.sanselan.formats.tiff.write.TiffOutputSet;
 import org.apache.sanselan.util.Debug;
@@ -144,29 +146,45 @@
 		writeSegmentsReplacingExif(os, pieces, null);
 	}
 
-	public void rewriteExifMetadata(ByteSource byteSource, OutputStream os,
-			Map params) throws ImageReadException, IOException,
-			ImageWriteException
-	{
-		JFIFPieces jfifPieces = analyzeJFIF(byteSource);
-		ArrayList pieces = jfifPieces.pieces;
-		GenericSegment exifSegment = jfifPieces.exifSegment;
-
-		byte exifBytes[] = exifSegment.bytes;
-		exifBytes = getBytearrayTail("trimmed exif bytes", exifBytes, 6);
-
-		TiffImageMetadata exifMetadata = (TiffImageMetadata) new TiffImageParser()
-				.getMetadata(exifBytes, params);
-
-		byte newBytes[] = writeExifSegment(exifMetadata, true);
-		//		exifSegment.bytes = newBytes;
-
-		//		ArrayList segments = readSegments(byteSource, null, false, true);
-
-		//		TiffImageMetadata exif = getExifMetadata(byteSource, params);
-
-		writeSegmentsReplacingExif(os, pieces, newBytes);
-	}
+//	public void rewriteExifMetadataLossless(ByteSource byteSource,
+//			OutputStream os, Map params) throws ImageReadException,
+//			IOException, ImageWriteException
+//	{
+//
+//		rewriteExifMetadata(MODE_LOSSLESS, byteSource, os, params);
+//	}
+//
+//	public void rewriteExifMetadataLossy(ByteSource byteSource,
+//			OutputStream os, Map params) throws ImageReadException,
+//			IOException, ImageWriteException
+//	{
+//
+//		rewriteExifMetadata(MODE_LOSSY, byteSource, os, params);
+//	}
+//
+//	private void rewriteExifMetadata(int mode, ByteSource byteSource,
+//			OutputStream os, Map params) throws ImageReadException,
+//			IOException, ImageWriteException
+//	{
+//		JFIFPieces jfifPieces = analyzeJFIF(byteSource);
+//		ArrayList pieces = jfifPieces.pieces;
+//		GenericSegment exifSegment = jfifPieces.exifSegment;
+//
+//		byte exifBytes[] = exifSegment.bytes;
+//		exifBytes = getBytearrayTail("trimmed exif bytes", exifBytes, 6);
+//
+//		TiffImageMetadata exifMetadata = (TiffImageMetadata) new TiffImageParser()
+//				.getMetadata(exifBytes, params);
+//
+//		byte newBytes[] = writeExifSegment(mode, exifMetadata, true);
+//		//		exifSegment.bytes = newBytes;
+//
+//		//		ArrayList segments = readSegments(byteSource, null, false, true);
+//
+//		//		TiffImageMetadata exif = getExifMetadata(byteSource, params);
+//
+//		writeSegmentsReplacingExif(os, pieces, newBytes);
+//	}
 
 	//	public void updateExifMetadata(ByteSource byteSource, OutputStream os,
 	//			ArrayList outputDirectories, Map params) throws ImageReadException,
@@ -188,10 +206,26 @@
 	//		writeSegmentsReplacingExif(os, pieces, newBytes);
 	//	}
 
-	public void updateExifMetadata(ByteSource byteSource, OutputStream os,
-			TiffOutputSet outputSet
-	//			, Map params
-	) throws ImageReadException, IOException, ImageWriteException
+	private static final int MODE_LOSSY = -1;
+	private static final int MODE_LOSSLESS = -2;
+
+	public void updateExifMetadataLossless(ByteSource byteSource,
+			OutputStream os, TiffOutputSet outputSet)
+			throws ImageReadException, IOException, ImageWriteException
+	{
+		updateExifMetadata(MODE_LOSSLESS, byteSource, os, outputSet);
+	}
+
+	public void updateExifMetadataLossy(ByteSource byteSource, OutputStream os,
+			TiffOutputSet outputSet) throws ImageReadException, IOException,
+			ImageWriteException
+	{
+		updateExifMetadata(MODE_LOSSY, byteSource, os, outputSet);
+	}
+
+	private void updateExifMetadata(int mode, ByteSource byteSource,
+			OutputStream os, TiffOutputSet outputSet)
+			throws ImageReadException, IOException, ImageWriteException
 	{
 		List outputDirectories = outputSet.getDirectories();
 		JFIFPieces jfifPieces = analyzeJFIF(byteSource);
@@ -203,7 +237,8 @@
 
 		int byteOrder = outputSet.byteOrder;
 
-		byte newBytes[] = writeExifSegment(outputDirectories, byteOrder, true);
+		byte newBytes[] = writeExifSegment(mode, byteOrder, outputDirectories,
+				true);
 
 		writeSegmentsReplacingExif(os, pieces, newBytes);
 	}
@@ -256,7 +291,7 @@
 		}
 	}
 
-	public byte[] writeExifSegment(TiffImageMetadata exif,
+	private byte[] writeExifSegment(int mode, TiffImageMetadata exif,
 			boolean includeEXIFPrefix) throws IOException, ImageWriteException
 	{
 		if (exif == null)
@@ -278,20 +313,55 @@
 			outputDirectories.add(outputDirectory);
 		}
 
-		return writeExifSegment(outputDirectories, byteOrder, includeEXIFPrefix);
+		return writeExifSegment(mode, byteOrder, outputDirectories,
+				includeEXIFPrefix);
 	}
 
-	public byte[] writeExifSegment(TiffOutputSet outputSet,
-			boolean includeEXIFPrefix) throws IOException, ImageWriteException
+//	private byte[] writeExifSegment(int mode, TiffOutputSet outputSet,
+//			boolean includeEXIFPrefix) throws IOException, ImageWriteException
+//	{
+//		List outputDirectories = outputSet.getDirectories();
+//
+//		return writeExifSegment(mode, outputSet.byteOrder, outputDirectories,
+//				includeEXIFPrefix);
+//	}
+
+	//
+	//	public byte[] writeExifSegmentLossy(List outputDirectories, int byteOrder,
+	//			boolean includeEXIFPrefix) throws IOException, ImageWriteException
+	//	{
+	//		TiffImageWriterBase writer = new TiffImageWriter(byteOrder);
+	//		return writeExifSegment(writer, outputDirectories, byteOrder,
+	//				includeEXIFPrefix);
+	//	}
+	//
+	//	private byte[] writeExifSegmentLossless(List outputDirectories,
+	//			int byteOrder, boolean includeEXIFPrefix) throws IOException,
+	//			ImageWriteException
+	//	{
+	//		TiffImageWriterBase writer = new TiffImageWriter(byteOrder);
+	//		return writeExifSegment(writer, outputDirectories, byteOrder,
+	//				includeEXIFPrefix);
+	//	}
+
+	private byte[] writeExifSegment(int mode, int byteOrder,
+			List outputDirectories, boolean includeEXIFPrefix)
+			throws IOException, ImageWriteException
 	{
-		List outputDirectories = outputSet.getDirectories();
+		TiffImageWriterBase writer;
+		if (mode == MODE_LOSSLESS)
+			writer = new TiffImageWriterLossless(byteOrder);
+		else if (mode == MODE_LOSSY)
+			writer = new TiffImageWriterLossy(byteOrder);
+		else
+			throw new ImageWriteException("Unknown TIFF write mode.");
 
-		return writeExifSegment(outputDirectories, outputSet.byteOrder,
-				includeEXIFPrefix);
+		return writeExifSegment(writer, outputDirectories, includeEXIFPrefix);
 	}
 
-	public byte[] writeExifSegment(List outputDirectories, int byteOrder,
-			boolean includeEXIFPrefix) throws IOException, ImageWriteException
+	private byte[] writeExifSegment(TiffImageWriterBase writer,
+			List outputDirectories, boolean includeEXIFPrefix)
+			throws IOException, ImageWriteException
 	{
 		ByteArrayOutputStream os = new ByteArrayOutputStream();
 
@@ -302,7 +372,7 @@
 			os.write(0);
 		}
 
-		new TiffImageWriter(byteOrder).writeDirectories(os, outputDirectories);
+		writer.writeDirectories(os, outputDirectories);
 
 		return os.toByteArray();
 	}

Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/TiffImageParser.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/TiffImageParser.java?rev=609512&r1=609511&r2=609512&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/TiffImageParser.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/TiffImageParser.java Sun Jan  6 20:39:11 2008
@@ -50,7 +50,7 @@
 import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterPalette;
 import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterRGB;
 import org.apache.sanselan.formats.tiff.photometricinterpreters.PhotometricInterpreterYCbCr;
-import org.apache.sanselan.formats.tiff.write.TiffImageWriter;
+import org.apache.sanselan.formats.tiff.write.TiffImageWriterLossy;
 import org.apache.sanselan.util.Debug;
 
 public class TiffImageParser extends ImageParser implements TiffConstants
@@ -138,12 +138,17 @@
 		int entryCount = read2Bytes("DirectoryEntryCount", is,
 				"Not a Valid TIFF File");
 
+//		Debug.debug("dirType", dirType);
+//		Debug.debug("offset", offset);
+
 		for (int i = 0; i < entryCount; i++)
 		{
 			int tag = read2Bytes("Tag", is, "Not a Valid TIFF File");
 			int type = read2Bytes("Type", is, "Not a Valid TIFF File");
 			int length = read4Bytes("Length", is, "Not a Valid TIFF File");
 
+//			Debug.debug("tag", tag);
+			
 			byte valueOffsetBytes[] = readByteArray("ValueOffset", 4, is,
 					"Not a Valid TIFF File");
 			int valueOffset = convertByteArrayToInt("ValueOffset",
@@ -174,6 +179,8 @@
 		if (debug)
 			System.out.println("");
 
+//		Debug.debug();
+
 		return new TiffDirectory(dirType, result, offset, nextDirectoryOffset);
 	}
 
@@ -1207,7 +1214,7 @@
 	public void writeImage(BufferedImage src, OutputStream os, Map params)
 			throws ImageWriteException, IOException
 	{
-		new TiffImageWriter().writeImage(src, os, params);
+		new TiffImageWriterLossy().writeImage(src, os, params);
 	}
 
 }

Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java?rev=609512&r1=609511&r2=609512&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java Sun Jan  6 20:39:11 2008
@@ -16,8 +16,18 @@
  */
 package org.apache.sanselan.formats.tiff.write;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sanselan.ImageWriteException;
 import org.apache.sanselan.common.BinaryConstants;
 import org.apache.sanselan.formats.tiff.constants.TiffConstants;
+import org.apache.sanselan.util.Debug;
 
 public abstract class TiffImageWriterBase
 		implements
@@ -36,6 +46,192 @@
 	public TiffImageWriterBase(int byteOrder)
 	{
 		this.byteOrder = byteOrder;
+	}
+
+	public abstract void writeDirectories(OutputStream os, List directories)
+			throws IOException, ImageWriteException;
+
+	protected TiffOutputSummary validateDirectories(List directories)
+			throws ImageWriteException
+	{
+		if (1 > directories.size())
+			throw new ImageWriteException("No directories.");
+
+		TiffOutputDirectory exifDirectory = null;
+		TiffOutputDirectory gpsDirectory = null;
+		TiffOutputDirectory interoperabilityDirectory = null;
+		TiffOutputField exifDirectoryOffsetField = null;
+		TiffOutputField gpsDirectoryOffsetField = null;
+		TiffOutputField interoperabilityDirectoryOffsetField = null;
+
+		ArrayList directoryIndices = new ArrayList();
+		Map directoryTypeMap = new HashMap();
+		for (int i = 0; i < directories.size(); i++)
+		{
+			TiffOutputDirectory directory = (TiffOutputDirectory) directories
+					.get(i);
+			int dirType = directory.type;
+			Integer key = new Integer(dirType);
+			directoryTypeMap.put(key, directory);
+			//			Debug.debug("validating dirType", dirType + " ("
+			//					+ directory.getFields().size() + " fields)");
+
+			if (dirType < 0)
+			{
+				switch (dirType)
+				{
+					case DIRECTORY_TYPE_EXIF :
+						if (exifDirectory != null)
+							throw new ImageWriteException(
+									"More than one EXIF directory.");
+						exifDirectory = directory;
+						break;
+
+					case DIRECTORY_TYPE_GPS :
+						if (gpsDirectory != null)
+							throw new ImageWriteException(
+									"More than one GPS directory.");
+						gpsDirectory = directory;
+						break;
+
+					case DIRECTORY_TYPE_INTEROPERABILITY :
+						if (interoperabilityDirectory != null)
+							throw new ImageWriteException(
+									"More than one Interoperability directory.");
+						interoperabilityDirectory = directory;
+						break;
+					default :
+						throw new ImageWriteException("Unknown directory: "
+								+ dirType);
+				}
+			}
+			else
+			{
+				if (directoryIndices.contains(key))
+					throw new ImageWriteException(
+							"More than one directory with index: " + dirType
+									+ ".");
+				directoryIndices.add(new Integer(dirType));
+				//				dirMap.put(arg0, arg1)
+			}
+
+			ArrayList fields = directory.getFields();
+			for (int j = 0; j < fields.size(); j++)
+			{
+				TiffOutputField field = (TiffOutputField) fields.get(j);
+				if (field.tagInfo.tag == EXIF_TAG_EXIF_OFFSET.tag)
+				{
+					if (exifDirectoryOffsetField != null)
+						throw new ImageWriteException(
+								"More than one Exif directory offset field.");
+					exifDirectoryOffsetField = field;
+				}
+				else if (field.tagInfo.tag == EXIF_TAG_INTEROP_OFFSET.tag)
+				{
+					if (interoperabilityDirectoryOffsetField != null)
+						throw new ImageWriteException(
+								"More than one Interoperability directory offset field.");
+					interoperabilityDirectoryOffsetField = field;
+				}
+				else if (field.tagInfo.tag == EXIF_TAG_GPSINFO.tag)
+				{
+					if (gpsDirectoryOffsetField != null)
+						throw new ImageWriteException(
+								"More than one GPS directory offset field.");
+					gpsDirectoryOffsetField = field;
+				}
+			}
+			//			directory.
+		}
+
+		if (directoryIndices.size() < 1)
+			throw new ImageWriteException("Missing root directory.");
+
+		// "normal" TIFF directories should have continous indices starting with 0, ie. 0, 1, 2...
+		Collections.sort(directoryIndices);
+
+		TiffOutputDirectory previousDirectory = null;
+		for (int i = 0; i < directoryIndices.size(); i++)
+		{
+			Integer index = (Integer) directoryIndices.get(i);
+			if (index.intValue() != i)
+				throw new ImageWriteException("Missing directory: " + i + ".");
+
+			// set up chain of directory references for "normal" directories.
+			TiffOutputDirectory directory = (TiffOutputDirectory) directoryTypeMap
+					.get(index);
+			if (null != previousDirectory)
+				previousDirectory.setNextDirectory(directory);
+			previousDirectory = directory;
+		}
+
+		TiffOutputDirectory rootDirectory = (TiffOutputDirectory) directoryTypeMap
+				.get(new Integer(DIRECTORY_TYPE_ROOT));
+
+		// prepare results
+		TiffOutputSummary result = new TiffOutputSummary(rootDirectory,
+				directoryTypeMap);
+
+		// make sure offset fields and offset'd directories correspond.
+		if (exifDirectory == null && exifDirectoryOffsetField != null)
+		{
+			// perhaps we should just discard field?
+			throw new ImageWriteException(
+					"Output set has Exif Directory Offset field, but no Exif Directory");
+		}
+		else if (exifDirectory != null)
+		{
+			if (exifDirectoryOffsetField == null)
+			{
+				exifDirectoryOffsetField = TiffOutputField.createOffsetField(
+						EXIF_TAG_EXIF_OFFSET, byteOrder);
+				rootDirectory.add(exifDirectoryOffsetField);
+			}
+
+			result.add(exifDirectory, exifDirectoryOffsetField);
+		}
+
+		if (gpsDirectory == null && gpsDirectoryOffsetField != null)
+		{
+			// perhaps we should just discard field?
+			throw new ImageWriteException(
+					"Output set has GPS Directory Offset field, but no GPS Directory");
+		}
+		else if (gpsDirectory != null)
+		{
+			if (gpsDirectoryOffsetField == null)
+			{
+				gpsDirectoryOffsetField = TiffOutputField.createOffsetField(
+						EXIF_TAG_GPSINFO, byteOrder);
+				rootDirectory.add(gpsDirectoryOffsetField);
+			}
+
+			result.add(gpsDirectory, gpsDirectoryOffsetField);
+		}
+
+		if (interoperabilityDirectory == null
+				&& interoperabilityDirectoryOffsetField != null)
+		{
+			// perhaps we should just discard field?
+			throw new ImageWriteException(
+					"Output set has Interoperability Directory Offset field, but no Interoperability Directory");
+		}
+		else if (interoperabilityDirectory != null)
+		{
+			if (interoperabilityDirectoryOffsetField == null)
+			{
+				interoperabilityDirectoryOffsetField = TiffOutputField
+						.createOffsetField(EXIF_TAG_INTEROP_OFFSET, byteOrder);
+				rootDirectory.add(interoperabilityDirectoryOffsetField);
+			}
+
+			result.add(interoperabilityDirectory,
+					interoperabilityDirectoryOffsetField);
+		}
+
+		return result;
+
+		//		Debug.debug();
 	}
 
 }

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java?rev=609512&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java Sun Jan  6 20:39:11 2008
@@ -0,0 +1,593 @@
+/*
+ * 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.tiff.write;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.common.BinaryOutputStream;
+import org.apache.sanselan.util.DebugOutputStream;
+
+public class TiffImageWriterLossless extends TiffImageWriterBase
+{
+
+	public TiffImageWriterLossless()
+	{
+	}
+
+	public TiffImageWriterLossless(int byteOrder)
+	{
+		super(byteOrder);
+	}
+
+	public void writeDirectories(OutputStream os, List directories)
+			throws IOException, ImageWriteException
+	{
+		TiffOutputSummary outputSummary = validateDirectories(directories);
+
+		//        Collections.sort(directories, Directory.COMPARATOR);
+
+		/**/
+
+		//        ImageDataInfo imageDataInfo = imageDataInfoStep(directories, imageData,
+		//                stripsNotTiles);
+		/**/
+
+		//		PointerDirectoriesInfo pointerDirectoriesInfo = pointerDirectoriesStep(directories);
+		/**/
+
+//		//        final int imageDataOffset = 
+//		calculateLengthsAndOffsetsStep(directories);
+//
+//		/**/
+//
+//		updateDirectoryPointersStep(pointerDirectoriesInfo);
+//
+//		/**/
+//
+//		//        updateImageDataOffsetsStep(imageDataInfo, imageDataOffset);
+//		/**/
+//
+//		DebugOutputStream dos = null;
+//		//        DebugOutputStream dos = new DebugOutputStream(os);
+//		//        os = dos;
+//		BinaryOutputStream bos = new BinaryOutputStream(os, byteOrder);
+//
+//		/**/
+//
+//		writeStep(bos, directories, dos);
+
+	}
+
+	//    public byte[][] getStrips(BufferedImage src, int fSamplesPerPixel,
+	//            int bitsPerSample, int rowsPerStrip)
+	//    {
+	//        int width = src.getWidth();
+	//        int height = src.getHeight();
+	//
+	//        int stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
+	//
+	//        byte result[][] = null;
+	//        { // Write Strips
+	//            result = new byte[stripCount][];
+	//
+	//            int remaining_rows = height;
+	//
+	//            for (int i = 0; i < stripCount; i++)
+	//            {
+	//                int rowsInStrip = Math.min(rowsPerStrip, remaining_rows);
+	//                remaining_rows -= rowsInStrip;
+	//
+	//                int bitsInStrip = bitsPerSample * rowsInStrip * width
+	//                        * fSamplesPerPixel;
+	//                int bytesInStrip = (bitsInStrip + 7) / 8;
+	//
+	//                byte uncompressed[] = new byte[bytesInStrip];
+	//
+	//                int counter = 0;
+	//                int y = i * rowsPerStrip;
+	//                int stop = i * rowsPerStrip + rowsPerStrip;
+	//
+	//                for (; (y < height) && (y < stop); y++)
+	//                {
+	//                    for (int x = 0; x < width; x++)
+	//                    {
+	//                        int rgb = src.getRGB(x, y);
+	//                        int red = 0xff & (rgb >> 16);
+	//                        int green = 0xff & (rgb >> 8);
+	//                        int blue = 0xff & (rgb >> 0);
+	//
+	//                        uncompressed[counter++] = (byte) red;
+	//                        uncompressed[counter++] = (byte) green;
+	//                        uncompressed[counter++] = (byte) blue;
+	//                    }
+	//                }
+	//
+	//                result[i] = uncompressed;
+	//            }
+	//
+	//        }
+	//
+	//        return result;
+	//    }
+	//
+	//    public void writeImage(BufferedImage src, OutputStream os, Map params)
+	//            throws ImageWriteException, IOException
+	//    {
+	//        //        writeImageNew(src, os, params);
+	//        //    }
+	//        //
+	//        //    public void writeImageNew(BufferedImage src, OutputStream os, Map params)
+	//        //            throws ImageWriteException, IOException
+	//        //    {
+	//
+	//        // make copy of params; we'll clear keys as we consume them.
+	//        params = new HashMap(params);
+	//
+	//        // clear format key.
+	//        if (params.containsKey(PARAM_KEY_FORMAT))
+	//            params.remove(PARAM_KEY_FORMAT);
+	//
+	//        int width = src.getWidth();
+	//        int height = src.getHeight();
+	//
+	//        //        BinaryOutputStream bos = new BinaryOutputStream(os, WRITE_BYTE_ORDER);
+	//        //
+	//        //        writeImageFileHeader(bos, WRITE_BYTE_ORDER);
+	//
+	//        //        ArrayList directoryFields = new ArrayList();
+	//
+	//        final int photometricInterpretation = 2; // TODO: 
+	//
+	//        int compression = TIFF_COMPRESSION_LZW; // LZW is default
+	//        if (params.containsKey(PARAM_KEY_COMPRESSION))
+	//        {
+	//            Object value = params.get(PARAM_KEY_COMPRESSION);
+	//            if (value != null)
+	//            {
+	//                if (!(value instanceof Number))
+	//                    throw new ImageWriteException(
+	//                            "Invalid compression parameter: " + value);
+	//                compression = ((Number) value).intValue();
+	//            }
+	//            params.remove(PARAM_KEY_COMPRESSION);
+	//        }
+	//
+	//        final int samplesPerPixel = 3; // TODO: 
+	//        final int bitsPerSample = 8; // TODO: 
+	//
+	//        //        int fRowsPerStrip; // TODO: 
+	//        int rowsPerStrip = 8000 / (width * samplesPerPixel); // TODO: 
+	//        rowsPerStrip = Math.max(1, rowsPerStrip); // must have at least one.
+	//
+	//        byte strips[][] = getStrips(src, samplesPerPixel, bitsPerSample,
+	//                rowsPerStrip);
+	//
+	//        //        int stripCount = (height + fRowsPerStrip - 1) / fRowsPerStrip;
+	//        //        int stripCount = strips.length;
+	//
+	//        if (params.size() > 0)
+	//        {
+	//            Object firstKey = params.keySet().iterator().next();
+	//            throw new ImageWriteException("Unknown parameter: " + firstKey);
+	//        }
+	//
+	//        //        System.out.println("width: " + width);
+	//        //        System.out.println("height: " + height);
+	//        //        System.out.println("fRowsPerStrip: " + fRowsPerStrip);
+	//        //        System.out.println("fSamplesPerPixel: " + fSamplesPerPixel);
+	//        //        System.out.println("stripCount: " + stripCount);
+	//
+	//        if (compression == TIFF_COMPRESSION_PACKBITS)
+	//        {
+	//            for (int i = 0; i < strips.length; i++)
+	//                strips[i] = new PackBits().compress(strips[i]);
+	//        }
+	//        else if (compression == TIFF_COMPRESSION_LZW)
+	//        {
+	//            for (int i = 0; i < strips.length; i++)
+	//            {
+	//                byte uncompressed[] = strips[i];
+	//
+	//                int LZWMinimumCodeSize = 8;
+	//
+	//                MyLZWCompressor compressor = new MyLZWCompressor(
+	//                        LZWMinimumCodeSize, BYTE_ORDER_MSB, true);
+	//                byte compressed[] = compressor.compress(uncompressed);
+	//
+	//                strips[i] = compressed;
+	//            }
+	//        }
+	//        else if (compression == TIFF_COMPRESSION_UNCOMPRESSED)
+	//        {
+	//            // do nothing.
+	//        }
+	//        else
+	//            throw new ImageWriteException(
+	//                    "Invalid compression parameter (Only LZW, Packbits and uncompressed supported).");
+	//
+	//        //        int stripOffsets[] = new int[stripCount];
+	//        //        int stripByteCounts[] = new int[stripCount];
+	//        //
+	//        //        for (int i = 0; i < strips.length; i++)
+	//        //            stripByteCounts[i] = strips[i].length;
+	//
+	//        TiffOutputDirectory directory = new TiffOutputDirectory(
+	//                TiffDirectory.DIRECTORY_TYPE_ROOT);
+	//
+	//        //        WriteField stripOffsetsField;
+	//
+	//        {
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_IMAGE_WIDTH, FIELD_TYPE_LONG, 1,
+	//                        FIELD_TYPE_LONG.writeData(new int[]{
+	//                            width,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            } 
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_IMAGE_LENGTH, FIELD_TYPE_LONG, 1,
+	//                        FIELD_TYPE_LONG.writeData(new int[]{
+	//                            height,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_PHOTOMETRIC_INTERPRETATION, FIELD_TYPE_SHORT,
+	//                        1, FIELD_TYPE_SHORT.writeData(new int[]{
+	//                            photometricInterpretation,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_COMPRESSION, FIELD_TYPE_SHORT, 1,
+	//                        FIELD_TYPE_SHORT.writeData(new int[]{
+	//                            compression,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_SAMPLES_PER_PIXEL, FIELD_TYPE_SHORT, 1,
+	//                        FIELD_TYPE_SHORT.writeData(new int[]{
+	//                            samplesPerPixel,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_BITS_PER_SAMPLE, FIELD_TYPE_SHORT, 3,
+	//                        FIELD_TYPE_SHORT.writeData(new int[]{
+	//                                bitsPerSample, bitsPerSample, bitsPerSample,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//            //            {
+	//            //                stripOffsetsField = new WriteField(TIFF_TAG_STRIP_OFFSETS,
+	//            //                        FIELD_TYPE_LONG, stripOffsets.length, FIELD_TYPE_LONG
+	//            //                                .writeData(stripOffsets, byteOrder));
+	//            //                directory.add(stripOffsetsField);
+	//            //            }
+	//            //            {
+	//            //                WriteField field = new WriteField(TIFF_TAG_STRIP_BYTE_COUNTS,
+	//            //                        FIELD_TYPE_LONG, stripByteCounts.length,
+	//            //                        FIELD_TYPE_LONG.writeData(stripByteCounts,
+	//            //                                WRITE_BYTE_ORDER));
+	//            //                directory.add(field);
+	//            //            }
+	//            {
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_ROWS_PER_STRIP, FIELD_TYPE_LONG, 1,
+	//                        FIELD_TYPE_LONG.writeData(new int[]{
+	//                            rowsPerStrip,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//
+	//            {
+	//                int resolutionUnit = 2;// inches.
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_RESOLUTION_UNIT, FIELD_TYPE_SHORT, 1,
+	//                        FIELD_TYPE_SHORT.writeData(new int[]{
+	//                            resolutionUnit,
+	//                        }, byteOrder));
+	//                directory.add(field);
+	//            }
+	//
+	//            {
+	//                int xResolution = 72;
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_XRESOLUTION, FIELD_TYPE_RATIONAL, 1,
+	//                        FIELD_TYPE_RATIONAL
+	//                                .writeData(xResolution, 1, byteOrder));
+	//                directory.add(field);
+	//            }
+	//
+	//            {
+	//                int yResolution = 72;
+	//                TiffOutputField field = new TiffOutputField(
+	//                        TIFF_TAG_YRESOLUTION, FIELD_TYPE_RATIONAL, 1,
+	//                        FIELD_TYPE_RATIONAL
+	//                                .writeData(yResolution, 1, byteOrder));
+	//                directory.add(field);
+	//            }
+	//
+	//        }
+	//
+	//        RawTiffImageData rawTiffImageData = new RawTiffImageData.Strips(strips);
+	//        directory.setRawTiffImageData(rawTiffImageData);
+	//
+	//        ArrayList directories = new ArrayList();
+	//        directories.add(directory);
+	//
+	//        writeDirectories(os, directories);
+	//    }
+	//
+	//    private void writeImageFileHeader(BinaryOutputStream bos)
+	//            throws IOException, ImageWriteException
+	//    {
+	//        bos.write(byteOrder);
+	//        bos.write(byteOrder);
+	//
+	//        bos.write2Bytes(42); // tiffVersion
+	//
+	//        int foffsetToFirstIFD = TIFF_HEADER_SIZE;
+	//
+	//        bos.write4Bytes(foffsetToFirstIFD);
+	//    }
+	//
+	//    static int imageDataPaddingLength(int dataLength)
+	//    {
+	//        return (4 - (dataLength % 4)) % 4;
+	//    }
+	//
+	//    private TiffOutputDirectory findDirectoryByType(List directories,
+	//            int type)
+	//    {
+	//        for (int i = 0; i < directories.size(); i++)
+	//        {
+	//            TiffOutputDirectory directory = (TiffOutputDirectory) directories
+	//                    .get(i);
+	//            if (directory.type == type)
+	//                return directory;
+	//        }
+	//        return null;
+	//    }
+	//
+	//    public void writeDirectories(OutputStream os, List directories)
+	//            throws IOException, ImageWriteException
+	//    {
+	//        //        Collections.sort(directories, Directory.COMPARATOR);
+	//
+	//        /**/
+	//
+	//        //        ImageDataInfo imageDataInfo = imageDataInfoStep(directories, imageData,
+	//        //                stripsNotTiles);
+	//        /**/
+	//
+	//        PointerDirectoriesInfo pointerDirectoriesInfo = pointerDirectoriesStep(directories);
+	//
+	//        /**/
+	//
+	//        //        final int imageDataOffset = 
+	//        calculateLengthsAndOffsetsStep(directories);
+	//
+	//        /**/
+	//
+	//        updateDirectoryPointersStep(pointerDirectoriesInfo);
+	//
+	//        /**/
+	//
+	//        //        updateImageDataOffsetsStep(imageDataInfo, imageDataOffset);
+	//        /**/
+	//
+	//        DebugOutputStream dos = null;
+	//        //        DebugOutputStream dos = new DebugOutputStream(os);
+	//        //        os = dos;
+	//        BinaryOutputStream bos = new BinaryOutputStream(os, byteOrder);
+	//
+	//        /**/
+	//
+	//        writeStep(bos, directories, dos);
+	//
+	//        /**/
+	//
+	//        //        writeImageDataStep(bos, directories, imageDataInfo);
+	//        /**/
+	//    }
+	//
+	//    private PointerDirectoriesInfo pointerDirectoriesStep(List directories)
+	//            throws ImageWriteException
+	//    {
+	//        TiffOutputDirectory firstDirectory = (TiffOutputDirectory) directories
+	//                .get(0);
+	//
+	//        TiffOutputField exifDirectoryOffsetField = null;
+	//        TiffOutputDirectory exifDirectory = findDirectoryByType(directories,
+	//                TiffDirectory.DIRECTORY_TYPE_EXIF);
+	//        if (null != exifDirectory)
+	//        {
+	//            exifDirectoryOffsetField = firstDirectory
+	//                    .findField(EXIF_TAG_GPSINFO);
+	//
+	//            if (null == exifDirectoryOffsetField)
+	//            {
+	//                exifDirectoryOffsetField = new TiffOutputField(
+	//                        EXIF_TAG_GPSINFO, FIELD_TYPE_LONG, 1,
+	//                        FIELD_TYPE_LONG.writeData(new int[]{
+	//                            0,
+	//                        }, byteOrder));
+	//                firstDirectory.add(exifDirectoryOffsetField);
+	//            }
+	//        }
+	//
+	//        TiffOutputField gpsDirectoryOffsetField = null;
+	//        TiffOutputDirectory gpsDirectory = findDirectoryByType(directories,
+	//                TiffDirectory.DIRECTORY_TYPE_GPS);
+	//        if (null != gpsDirectory)
+	//        {
+	//            gpsDirectoryOffsetField = firstDirectory
+	//                    .findField(EXIF_TAG_GPSINFO);
+	//            if (null == gpsDirectoryOffsetField)
+	//            {
+	//                gpsDirectoryOffsetField = new TiffOutputField(
+	//                        EXIF_TAG_GPSINFO, FIELD_TYPE_LONG, 1,
+	//                        FIELD_TYPE_LONG.writeData(new int[]{
+	//                            0,
+	//                        }, byteOrder));
+	//                firstDirectory.add(gpsDirectoryOffsetField);
+	//            }
+	//        }
+	//
+	//        TiffOutputField iteroperabilityDirectoryOffsetField = null;
+	//        TiffOutputDirectory iteroperabilityDirectory = findDirectoryByType(
+	//                directories, TiffDirectory.DIRECTORY_TYPE_INTEROPERABILITY);
+	//        if (null != iteroperabilityDirectory)
+	//        {
+	//            if (null == exifDirectory)
+	//                throw new ImageWriteException(
+	//                        "Can't write iteroperability directory without EXIF directory.");
+	//
+	//            iteroperabilityDirectoryOffsetField = exifDirectory
+	//                    .findField(EXIF_TAG_INTEROP_OFFSET);
+	//            if (null == iteroperabilityDirectoryOffsetField)
+	//            {
+	//                iteroperabilityDirectoryOffsetField = new TiffOutputField(
+	//                        EXIF_TAG_INTEROP_OFFSET, FIELD_TYPE_LONG,
+	//                        1, FIELD_TYPE_LONG.writeData(new int[]{
+	//                            0,
+	//                        }, byteOrder));
+	//                exifDirectory.add(iteroperabilityDirectoryOffsetField);
+	//            }
+	//        }
+	//
+	//        return new PointerDirectoriesInfo(exifDirectoryOffsetField,
+	//                exifDirectory, gpsDirectoryOffsetField, gpsDirectory,
+	//                iteroperabilityDirectoryOffsetField, iteroperabilityDirectory);
+	//
+	//    }
+	//
+	//    private void calculateLengthsAndOffsetsStep(List directories)
+	//            throws IOException, ImageWriteException
+	//    //    private int calculateLengthsAndOffsetsStep(ArrayList directories)
+	//    {
+	//        // Calculate lengths and offsets
+	//        int offset = TIFF_HEADER_SIZE;
+	//
+	//        TiffOutputDirectory previousDirectory = null;
+	//        for (int i = 0; i < directories.size(); i++)
+	//        {
+	//            TiffOutputDirectory directory = (TiffOutputDirectory) directories
+	//                    .get(i);
+	//
+	//            // fields must be written in ascending order.
+	//            directory.sortFields();
+	//
+	//            directory.offset = offset;
+	//
+	//            if (directory.type == TiffDirectory.DIRECTORY_TYPE_EXIF
+	//                    || directory.type == TiffDirectory.DIRECTORY_TYPE_GPS
+	//                    || directory.type == TiffDirectory.DIRECTORY_TYPE_INTEROPERABILITY)
+	//            {
+	//                // "pointer" directories don't partcipate in normal TIFF directory chain.
+	//                directory.calculateLengths(byteOrder);
+	//                offset += directory.totalLength;
+	//            }
+	//            else
+	//            {
+	//                if (null != previousDirectory)
+	//                    previousDirectory.nextDirectoryOffset = offset;
+	//
+	//                directory.calculateLengths(byteOrder);
+	//                offset += directory.totalLength;
+	//
+	//                previousDirectory = directory;
+	//            }
+	//        }
+	//        //        return offset;
+	//    }
+	//
+	//    private void updateDirectoryPointersStep(
+	//            PointerDirectoriesInfo pointerDirectoriesInfo)
+	//    {
+	//        if (null != pointerDirectoriesInfo.exifDirectory)
+	//        {
+	//            byte value[] = FIELD_TYPE_LONG.writeData(new int[]{
+	//                pointerDirectoriesInfo.exifDirectory.offset,
+	//            }, byteOrder);
+	//            pointerDirectoriesInfo.exifDirectoryOffsetField.setData(value);
+	//        }
+	//
+	//        if (null != pointerDirectoriesInfo.gpsDirectory)
+	//        {
+	//            byte value[] = FIELD_TYPE_LONG.writeData(new int[]{
+	//                pointerDirectoriesInfo.gpsDirectory.offset,
+	//            }, byteOrder);
+	//            pointerDirectoriesInfo.gpsDirectoryOffsetField.setData(value);
+	//        }
+	//
+	//        if (null != pointerDirectoriesInfo.iteroperabilityDirectory)
+	//        {
+	//            byte value[] = FIELD_TYPE_LONG.writeData(new int[]{
+	//                pointerDirectoriesInfo.iteroperabilityDirectory.offset,
+	//            }, byteOrder);
+	//            pointerDirectoriesInfo.iteroperabilityDirectoryOffsetField
+	//                    .setData(value);
+	//        }
+	//    }
+	//
+	//    private void writeStep(BinaryOutputStream bos, List directories,
+	//            DebugOutputStream dos) throws IOException, ImageWriteException
+	//    {
+	//        writeImageFileHeader(bos);
+	//
+	//        long count, lastCount = 0;
+	//
+	//        if (null != dos)
+	//        {
+	//            count = dos.count();
+	//            Debug.debug("image header" + " start: " + lastCount + ", end: "
+	//                    + dos.count() + ", length: " + (count - lastCount));
+	//            lastCount = count;
+	//        }
+	//
+	//        for (int i = 0; i < directories.size(); i++)
+	//        {
+	//            TiffOutputDirectory directory = (TiffOutputDirectory) directories
+	//                    .get(i);
+	//            directory.write(bos);
+	//
+	//            if (null != dos)
+	//            {
+	//                count = dos.count();
+	//                Debug.debug("directory("
+	//                        + TiffDirectory.description(directory.type) + ")"
+	//                        + " start: " + lastCount + ", end: " + dos.count()
+	//                        + ", length: " + (count - lastCount)
+	//                        + ", expected length: " + directory.totalLength);
+	//                lastCount = count;
+	//            }
+	//        }
+	//    }
+
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossy.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossy.java?rev=609512&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossy.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossy.java Sun Jan  6 20:39:11 2008
@@ -0,0 +1,459 @@
+/*
+ * 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.tiff.write;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sanselan.ImageWriteException;
+import org.apache.sanselan.common.BinaryOutputStream;
+import org.apache.sanselan.common.PackBits;
+import org.apache.sanselan.common.mylzw.MyLZWCompressor;
+import org.apache.sanselan.formats.tiff.RawTiffImageData;
+import org.apache.sanselan.formats.tiff.TiffDirectory;
+import org.apache.sanselan.util.Debug;
+import org.apache.sanselan.util.DebugOutputStream;
+
+public class TiffImageWriterLossy extends TiffImageWriterBase
+{
+
+	public TiffImageWriterLossy()
+	{
+	}
+
+	public TiffImageWriterLossy(int byteOrder)
+	{
+		super(byteOrder);
+	}
+
+	public byte[][] getStrips(BufferedImage src, int fSamplesPerPixel,
+			int bitsPerSample, int rowsPerStrip)
+	{
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		int stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
+
+		byte result[][] = null;
+		{ // Write Strips
+			result = new byte[stripCount][];
+
+			int remaining_rows = height;
+
+			for (int i = 0; i < stripCount; i++)
+			{
+				int rowsInStrip = Math.min(rowsPerStrip, remaining_rows);
+				remaining_rows -= rowsInStrip;
+
+				int bitsInStrip = bitsPerSample * rowsInStrip * width
+						* fSamplesPerPixel;
+				int bytesInStrip = (bitsInStrip + 7) / 8;
+
+				byte uncompressed[] = new byte[bytesInStrip];
+
+				int counter = 0;
+				int y = i * rowsPerStrip;
+				int stop = i * rowsPerStrip + rowsPerStrip;
+
+				for (; (y < height) && (y < stop); y++)
+				{
+					for (int x = 0; x < width; x++)
+					{
+						int rgb = src.getRGB(x, y);
+						int red = 0xff & (rgb >> 16);
+						int green = 0xff & (rgb >> 8);
+						int blue = 0xff & (rgb >> 0);
+
+						uncompressed[counter++] = (byte) red;
+						uncompressed[counter++] = (byte) green;
+						uncompressed[counter++] = (byte) blue;
+					}
+				}
+
+				result[i] = uncompressed;
+			}
+
+		}
+
+		return result;
+	}
+
+	public void writeImage(BufferedImage src, OutputStream os, Map params)
+			throws ImageWriteException, IOException
+	{
+		//        writeImageNew(src, os, params);
+		//    }
+		//
+		//    public void writeImageNew(BufferedImage src, OutputStream os, Map params)
+		//            throws ImageWriteException, IOException
+		//    {
+
+		// make copy of params; we'll clear keys as we consume them.
+		params = new HashMap(params);
+
+		// clear format key.
+		if (params.containsKey(PARAM_KEY_FORMAT))
+			params.remove(PARAM_KEY_FORMAT);
+
+		int width = src.getWidth();
+		int height = src.getHeight();
+
+		//        BinaryOutputStream bos = new BinaryOutputStream(os, WRITE_BYTE_ORDER);
+		//
+		//        writeImageFileHeader(bos, WRITE_BYTE_ORDER);
+
+		//        ArrayList directoryFields = new ArrayList();
+
+		final int photometricInterpretation = 2; // TODO: 
+
+		int compression = TIFF_COMPRESSION_LZW; // LZW is default
+		if (params.containsKey(PARAM_KEY_COMPRESSION))
+		{
+			Object value = params.get(PARAM_KEY_COMPRESSION);
+			if (value != null)
+			{
+				if (!(value instanceof Number))
+					throw new ImageWriteException(
+							"Invalid compression parameter: " + value);
+				compression = ((Number) value).intValue();
+			}
+			params.remove(PARAM_KEY_COMPRESSION);
+		}
+
+		final int samplesPerPixel = 3; // TODO: 
+		final int bitsPerSample = 8; // TODO: 
+
+		//        int fRowsPerStrip; // TODO: 
+		int rowsPerStrip = 8000 / (width * samplesPerPixel); // TODO: 
+		rowsPerStrip = Math.max(1, rowsPerStrip); // must have at least one.
+
+		byte strips[][] = getStrips(src, samplesPerPixel, bitsPerSample,
+				rowsPerStrip);
+
+		//        int stripCount = (height + fRowsPerStrip - 1) / fRowsPerStrip;
+		//        int stripCount = strips.length;
+
+		if (params.size() > 0)
+		{
+			Object firstKey = params.keySet().iterator().next();
+			throw new ImageWriteException("Unknown parameter: " + firstKey);
+		}
+
+		//        System.out.println("width: " + width);
+		//        System.out.println("height: " + height);
+		//        System.out.println("fRowsPerStrip: " + fRowsPerStrip);
+		//        System.out.println("fSamplesPerPixel: " + fSamplesPerPixel);
+		//        System.out.println("stripCount: " + stripCount);
+
+		if (compression == TIFF_COMPRESSION_PACKBITS)
+		{
+			for (int i = 0; i < strips.length; i++)
+				strips[i] = new PackBits().compress(strips[i]);
+		}
+		else if (compression == TIFF_COMPRESSION_LZW)
+		{
+			for (int i = 0; i < strips.length; i++)
+			{
+				byte uncompressed[] = strips[i];
+
+				int LZWMinimumCodeSize = 8;
+
+				MyLZWCompressor compressor = new MyLZWCompressor(
+						LZWMinimumCodeSize, BYTE_ORDER_MSB, true);
+				byte compressed[] = compressor.compress(uncompressed);
+
+				strips[i] = compressed;
+			}
+		}
+		else if (compression == TIFF_COMPRESSION_UNCOMPRESSED)
+		{
+			// do nothing.
+		}
+		else
+			throw new ImageWriteException(
+					"Invalid compression parameter (Only LZW, Packbits and uncompressed supported).");
+
+		//        int stripOffsets[] = new int[stripCount];
+		//        int stripByteCounts[] = new int[stripCount];
+		//
+		//        for (int i = 0; i < strips.length; i++)
+		//            stripByteCounts[i] = strips[i].length;
+
+		TiffOutputDirectory directory = new TiffOutputDirectory(
+				TiffDirectory.DIRECTORY_TYPE_ROOT);
+
+		//        WriteField stripOffsetsField;
+
+		{
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_IMAGE_WIDTH, FIELD_TYPE_LONG, 1,
+						FIELD_TYPE_LONG.writeData(new int[]{
+							width,
+						}, byteOrder));
+				directory.add(field);
+			}
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_IMAGE_LENGTH, FIELD_TYPE_LONG, 1,
+						FIELD_TYPE_LONG.writeData(new int[]{
+							height,
+						}, byteOrder));
+				directory.add(field);
+			}
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_PHOTOMETRIC_INTERPRETATION, FIELD_TYPE_SHORT,
+						1, FIELD_TYPE_SHORT.writeData(new int[]{
+							photometricInterpretation,
+						}, byteOrder));
+				directory.add(field);
+			}
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_COMPRESSION, FIELD_TYPE_SHORT, 1,
+						FIELD_TYPE_SHORT.writeData(new int[]{
+							compression,
+						}, byteOrder));
+				directory.add(field);
+			}
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_SAMPLES_PER_PIXEL, FIELD_TYPE_SHORT, 1,
+						FIELD_TYPE_SHORT.writeData(new int[]{
+							samplesPerPixel,
+						}, byteOrder));
+				directory.add(field);
+			}
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_BITS_PER_SAMPLE, FIELD_TYPE_SHORT, 3,
+						FIELD_TYPE_SHORT.writeData(new int[]{
+								bitsPerSample, bitsPerSample, bitsPerSample,
+						}, byteOrder));
+				directory.add(field);
+			}
+			//            {
+			//                stripOffsetsField = new WriteField(TIFF_TAG_STRIP_OFFSETS,
+			//                        FIELD_TYPE_LONG, stripOffsets.length, FIELD_TYPE_LONG
+			//                                .writeData(stripOffsets, byteOrder));
+			//                directory.add(stripOffsetsField);
+			//            }
+			//            {
+			//                WriteField field = new WriteField(TIFF_TAG_STRIP_BYTE_COUNTS,
+			//                        FIELD_TYPE_LONG, stripByteCounts.length,
+			//                        FIELD_TYPE_LONG.writeData(stripByteCounts,
+			//                                WRITE_BYTE_ORDER));
+			//                directory.add(field);
+			//            }
+			{
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_ROWS_PER_STRIP, FIELD_TYPE_LONG, 1,
+						FIELD_TYPE_LONG.writeData(new int[]{
+							rowsPerStrip,
+						}, byteOrder));
+				directory.add(field);
+			}
+
+			{
+				int resolutionUnit = 2;// inches.
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_RESOLUTION_UNIT, FIELD_TYPE_SHORT, 1,
+						FIELD_TYPE_SHORT.writeData(new int[]{
+							resolutionUnit,
+						}, byteOrder));
+				directory.add(field);
+			}
+
+			{
+				int xResolution = 72;
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_XRESOLUTION, FIELD_TYPE_RATIONAL, 1,
+						FIELD_TYPE_RATIONAL
+								.writeData(xResolution, 1, byteOrder));
+				directory.add(field);
+			}
+
+			{
+				int yResolution = 72;
+				TiffOutputField field = new TiffOutputField(
+						TIFF_TAG_YRESOLUTION, FIELD_TYPE_RATIONAL, 1,
+						FIELD_TYPE_RATIONAL
+								.writeData(yResolution, 1, byteOrder));
+				directory.add(field);
+			}
+
+		}
+
+		RawTiffImageData rawTiffImageData = new RawTiffImageData.Strips(strips);
+		directory.setRawTiffImageData(rawTiffImageData);
+
+		ArrayList directories = new ArrayList();
+		directories.add(directory);
+
+		writeDirectories(os, directories);
+	}
+
+	private void writeImageFileHeader(BinaryOutputStream bos)
+			throws IOException, ImageWriteException
+	{
+		bos.write(byteOrder);
+		bos.write(byteOrder);
+
+		bos.write2Bytes(42); // tiffVersion
+
+		int foffsetToFirstIFD = TIFF_HEADER_SIZE;
+
+		bos.write4Bytes(foffsetToFirstIFD);
+	}
+
+	static int imageDataPaddingLength(int dataLength)
+	{
+		return (4 - (dataLength % 4)) % 4;
+	}
+
+	private TiffOutputDirectory findDirectoryByType(List directories, int type)
+	{
+		for (int i = 0; i < directories.size(); i++)
+		{
+			TiffOutputDirectory directory = (TiffOutputDirectory) directories
+					.get(i);
+			if (directory.type == type)
+				return directory;
+		}
+		return null;
+	}
+
+	public void writeDirectories(OutputStream os, List directories)
+			throws IOException, ImageWriteException
+	{
+
+		TiffOutputSummary outputSummary = validateDirectories(directories);
+
+		//        Collections.sort(directories, Directory.COMPARATOR);
+
+		/**/
+
+		//        ImageDataInfo imageDataInfo = imageDataInfoStep(directories, imageData,
+		//                stripsNotTiles);
+		/**/
+
+		//		PointerDirectoriesInfo pointerDirectoriesInfo = pointerDirectoriesStep(directories);
+		/**/
+
+		//        final int imageDataOffset = 
+		calculateLengthsAndOffsetsStep(directories);
+
+		/**/
+
+		outputSummary.updateOffsets(byteOrder);
+
+		/**/
+
+		//        updateImageDataOffsetsStep(imageDataInfo, imageDataOffset);
+		/**/
+
+		DebugOutputStream dos = null;
+		//        DebugOutputStream dos = new DebugOutputStream(os);
+		//        os = dos;
+		BinaryOutputStream bos = new BinaryOutputStream(os, byteOrder);
+
+		/**/
+
+		writeStep(bos, directories, dos);
+
+		/**/
+
+		//        writeImageDataStep(bos, directories, imageDataInfo);
+		/**/
+	}
+
+	private void calculateLengthsAndOffsetsStep(List directories)
+			throws IOException, ImageWriteException
+	//    private int calculateLengthsAndOffsetsStep(ArrayList directories)
+	{
+		// Calculate lengths and offsets
+		int offset = TIFF_HEADER_SIZE;
+
+		for (int i = 0; i < directories.size(); i++)
+		{
+			TiffOutputDirectory directory = (TiffOutputDirectory) directories
+					.get(i);
+
+			// fields must be written in ascending order.
+			directory.sortFields();
+
+			directory.offset = offset;
+
+			if (directory.type == TiffDirectory.DIRECTORY_TYPE_EXIF
+					|| directory.type == TiffDirectory.DIRECTORY_TYPE_GPS
+					|| directory.type == TiffDirectory.DIRECTORY_TYPE_INTEROPERABILITY)
+			{
+				// "pointer" directories don't partcipate in normal TIFF directory chain.
+				directory.calculateLengths(byteOrder);
+				offset += directory.totalLength;
+			}
+			else
+			{
+				directory.calculateLengths(byteOrder);
+				offset += directory.totalLength;
+			}
+		}
+		//        return offset;
+	}
+
+	private void writeStep(BinaryOutputStream bos, List directories,
+			DebugOutputStream dos) throws IOException, ImageWriteException
+	{
+		writeImageFileHeader(bos);
+
+		long count, lastCount = 0;
+
+		if (null != dos)
+		{
+			count = dos.count();
+			Debug.debug("image header" + " start: " + lastCount + ", end: "
+					+ dos.count() + ", length: " + (count - lastCount));
+			lastCount = count;
+		}
+
+		for (int i = 0; i < directories.size(); i++)
+		{
+			TiffOutputDirectory directory = (TiffOutputDirectory) directories
+					.get(i);
+			directory.write(bos);
+
+			if (null != dos)
+			{
+				count = dos.count();
+				Debug.debug("directory("
+						+ TiffDirectory.description(directory.type) + ")"
+						+ " start: " + lastCount + ", end: " + dos.count()
+						+ ", length: " + (count - lastCount)
+						+ ", expected length: " + directory.totalLength);
+				lastCount = count;
+			}
+		}
+	}
+
+}

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputDirectory.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputDirectory.java?rev=609512&r1=609511&r2=609512&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputDirectory.java (original)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputDirectory.java Sun Jan  6 20:39:11 2008
@@ -36,9 +36,15 @@
 	public int internalLength = UNDEFINED_VALUE;
 	public int totalLength = UNDEFINED_VALUE;
 	public int offset = UNDEFINED_VALUE;
-	public int nextDirectoryOffset = UNDEFINED_VALUE;
 	private final ArrayList fields = new ArrayList();
 
+	private TiffOutputDirectory nextDirectory = null;
+
+	public void setNextDirectory(TiffOutputDirectory nextDirectory)
+	{
+		this.nextDirectory = nextDirectory;
+	}
+
 	public TiffOutputDirectory(final int type)
 	{
 		this.type = type;
@@ -93,9 +99,9 @@
 		tiffImageDataInfoStep(byteOrder);
 		jpegImageDataInfoStep(byteOrder);
 
-		internalLength = TiffImageWriter.TIFF_ENTRY_LENGTH * fields.size()
-				+ TiffImageWriter.TIFF_DIRECTORY_HEADER_LENGTH
-				+ TiffImageWriter.TIFF_DIRECTORY_FOOTER_LENGTH;
+		internalLength = TiffImageWriterLossy.TIFF_ENTRY_LENGTH * fields.size()
+				+ TiffImageWriterLossy.TIFF_DIRECTORY_HEADER_LENGTH
+				+ TiffImageWriterLossy.TIFF_DIRECTORY_FOOTER_LENGTH;
 
 		totalLength = internalLength;
 
@@ -116,7 +122,7 @@
 		{
 			int imageDataOffset = offset + totalLength;
 			totalLength += rawJpegImageData.length;
-			totalLength += TiffImageWriter
+			totalLength += TiffImageWriterLossy
 					.imageDataPaddingLength(rawJpegImageData.length);
 			updateJpegImageDataOffsetsStep(imageDataOffset, byteOrder);
 		}
@@ -156,6 +162,10 @@
 					nextSeperateValueOffset);
 		}
 
+		int nextDirectoryOffset = 0;
+		if(nextDirectory!=null)
+			nextDirectoryOffset = nextDirectory.offset;
+		
 		// Write nextDirectoryOffset
 		if (nextDirectoryOffset == UNDEFINED_VALUE)
 			bos.write4Bytes(0);
@@ -177,7 +187,7 @@
 				bos.writeByteArray(imageData[i]);
 				int imageDataByteCount = imageData[i].length;
 
-				int remainder = TiffImageWriter
+				int remainder = TiffImageWriterLossy
 						.imageDataPaddingLength(imageDataByteCount);
 				for (int j = 0; j < remainder; j++)
 					bos.write(0);
@@ -188,7 +198,7 @@
 		{
 			//				byte imageData[][] = rawJpegImageData.getRawImageData();
 			bos.writeByteArray(rawJpegImageData);
-			int remainder = TiffImageWriter
+			int remainder = TiffImageWriterLossy
 					.imageDataPaddingLength(rawJpegImageData.length);
 			for (int j = 0; j < remainder; j++)
 				bos.write(0);
@@ -219,7 +229,7 @@
 			imageDataByteCounts[i] = imageData[i].length;
 			totalLength += imageData[i].length;
 
-			totalLength += TiffImageWriter
+			totalLength += TiffImageWriterLossy
 					.imageDataPaddingLength(imageData[i].length);
 		}
 
@@ -227,17 +237,17 @@
 		{
 			TagInfo tagInfo;
 			if (stripsNotTiles)
-				tagInfo = TiffImageWriter.TIFF_TAG_STRIP_OFFSETS;
+				tagInfo = TiffImageWriterLossy.TIFF_TAG_STRIP_OFFSETS;
 			else
-				tagInfo = TiffImageWriter.TIFF_TAG_TILE_OFFSETS;
+				tagInfo = TiffImageWriterLossy.TIFF_TAG_TILE_OFFSETS;
 
 			imageDataOffsetsField = findField(tagInfo);
 			if (null == imageDataOffsetsField)
 			{
 				imageDataOffsetsField = new TiffOutputField(tagInfo,
-						TiffImageWriter.FIELD_TYPE_LONG,
+						TiffImageWriterLossy.FIELD_TYPE_LONG,
 						imageDataOffsets.length,
-						TiffImageWriter.FIELD_TYPE_LONG.writeData(
+						TiffImageWriterLossy.FIELD_TYPE_LONG.writeData(
 								imageDataOffsets, byteOrder));
 				add(imageDataOffsetsField);
 			}
@@ -245,17 +255,17 @@
 		{
 			TagInfo tagInfo;
 			if (stripsNotTiles)
-				tagInfo = TiffImageWriter.TIFF_TAG_STRIP_BYTE_COUNTS;
+				tagInfo = TiffImageWriterLossy.TIFF_TAG_STRIP_BYTE_COUNTS;
 			else
-				tagInfo = TiffImageWriter.TIFF_TAG_TILE_BYTE_COUNTS;
+				tagInfo = TiffImageWriterLossy.TIFF_TAG_TILE_BYTE_COUNTS;
 
-			byte data[] = TiffImageWriter.FIELD_TYPE_LONG.writeData(
+			byte data[] = TiffImageWriterLossy.FIELD_TYPE_LONG.writeData(
 					imageDataByteCounts, byteOrder);
 
 			TiffOutputField field = findField(tagInfo);
 			if (null == field)
 				add(new TiffOutputField(tagInfo,
-						TiffImageWriter.FIELD_TYPE_LONG,
+						TiffImageWriterLossy.FIELD_TYPE_LONG,
 						imageDataByteCounts.length, data));
 			else
 				field.setData(data);
@@ -279,30 +289,32 @@
 
 		// Append imageData-related fields to first directory
 		{
-			TagInfo tagInfo = TiffImageWriter.TIFF_TAG_JPEG_INTERCHANGE_FORMAT;
+			TagInfo tagInfo = TiffImageWriterLossy.TIFF_TAG_JPEG_INTERCHANGE_FORMAT;
 
 			jpegImageDataOffsetField = findField(tagInfo);
 			if (null == jpegImageDataOffsetField)
 			{
 				jpegImageDataOffsetField = new TiffOutputField(tagInfo,
-						TiffImageWriter.FIELD_TYPE_LONG, 1,
-						TiffImageWriter.FIELD_TYPE_LONG.writeData(new int[]{
-							0,
-						}, byteOrder));
+						TiffImageWriterLossy.FIELD_TYPE_LONG, 1,
+						TiffImageWriterLossy.FIELD_TYPE_LONG.writeData(
+								new int[]{
+									0,
+								}, byteOrder));
 				add(jpegImageDataOffsetField);
 			}
 		}
 		{
-			TagInfo tagInfo = TiffImageWriter.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH;
+			TagInfo tagInfo = TiffImageWriterLossy.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH;
 
-			byte data[] = TiffImageWriter.FIELD_TYPE_LONG.writeData(new int[]{
-				rawJpegImageData.length,
-			}, byteOrder);
+			byte data[] = TiffImageWriterLossy.FIELD_TYPE_LONG.writeData(
+					new int[]{
+						rawJpegImageData.length,
+					}, byteOrder);
 
 			TiffOutputField field = findField(tagInfo);
 			if (null == field)
 				add(new TiffOutputField(tagInfo,
-						TiffImageWriter.FIELD_TYPE_LONG, 1, data));
+						TiffImageWriterLossy.FIELD_TYPE_LONG, 1, data));
 			else
 				field.setData(data);
 		}
@@ -318,12 +330,12 @@
 			imageDataInfo.imageDataOffsets[i] = currentOffset;
 			currentOffset += imageDataInfo.imageDataByteCounts[i];
 
-			currentOffset += TiffImageWriter
+			currentOffset += TiffImageWriterLossy
 					.imageDataPaddingLength(imageDataInfo.imageDataByteCounts[i]);
 		}
 
 		imageDataInfo.imageDataOffsetsField
-				.setData(TiffImageWriter.FIELD_TYPE_LONG.writeData(
+				.setData(TiffImageWriterLossy.FIELD_TYPE_LONG.writeData(
 						imageDataInfo.imageDataOffsets, byteOrder));
 		//			}
 	}
@@ -331,7 +343,7 @@
 	private void updateJpegImageDataOffsetsStep(final int imageDataOffset,
 			int byteOrder) throws IOException, ImageWriteException
 	{
-		jpegImageDataOffsetField.setData(TiffImageWriter.FIELD_TYPE_LONG
+		jpegImageDataOffsetField.setData(TiffImageWriterLossy.FIELD_TYPE_LONG
 				.writeData(new int[]{
 					imageDataOffset,
 				}, byteOrder));

Added: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputSummary.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputSummary.java?rev=609512&view=auto
==============================================================================
--- incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputSummary.java (added)
+++ incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputSummary.java Sun Jan  6 20:39:11 2008
@@ -0,0 +1,98 @@
+/*
+ * 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.tiff.write;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sanselan.formats.tiff.constants.TiffConstants;
+
+class TiffOutputSummary implements TiffConstants
+{
+	public final TiffOutputDirectory rootDirectory;
+	public final Map directoryTypeMap;
+
+	public TiffOutputSummary(final TiffOutputDirectory rootDirectory,
+			final Map directoryTypeMap)
+	{
+		this.rootDirectory = rootDirectory;
+		this.directoryTypeMap = directoryTypeMap;
+	}
+
+	private static class Offset
+	{
+		public final TiffOutputDirectory directory;
+		public final TiffOutputField directoryOffsetField;
+
+		public Offset(final TiffOutputDirectory directory,
+				final TiffOutputField directoryOffsetField)
+		{
+			super();
+			this.directoryOffsetField = directoryOffsetField;
+			this.directory = directory;
+		}
+	}
+
+	private List offsets = new ArrayList();
+
+	public void add(final TiffOutputDirectory directory,
+			final TiffOutputField directoryOffsetField)
+	{
+		offsets.add(new Offset(directory, directoryOffsetField));
+	}
+
+	public void updateOffsets(int byteOrder)
+	{
+		for (int i = 0; i < offsets.size(); i++)
+		{
+			Offset offset = (Offset) offsets.get(i);
+
+			byte value[] = FIELD_TYPE_LONG.writeData(new int[]{
+				offset.directory.offset,
+			}, byteOrder);
+			offset.directoryOffsetField.setData(value);
+		}
+	}
+
+	//	public PointerDirectoriesInfo(
+	//){}
+	//	
+	//	public final TiffOutputField exifDirectoryOffsetField;
+	//	public final TiffOutputDirectory exifDirectory;
+	//	public final TiffOutputField gpsDirectoryOffsetField;
+	//	public final TiffOutputDirectory gpsDirectory;
+	//	public final TiffOutputField interoperabilityDirectoryOffsetField;
+	//	public final TiffOutputDirectory interoperabilityDirectory;
+	//
+	//	public PointerDirectoriesInfo(
+	//			final TiffOutputField exifDirectoryOffsetField,
+	//			final TiffOutputDirectory exifDirectory,
+	//			final TiffOutputField gpsDirectoryOffsetField,
+	//			final TiffOutputDirectory gpsDirectory,
+	//			final TiffOutputField interoperabilityDirectoryOffsetField,
+	//			final TiffOutputDirectory interoperabilityDirectory)
+	//	{
+	//		this.exifDirectoryOffsetField = exifDirectoryOffsetField;
+	//		this.exifDirectory = exifDirectory;
+	//		this.gpsDirectoryOffsetField = gpsDirectoryOffsetField;
+	//		this.gpsDirectory = gpsDirectory;
+	//		this.interoperabilityDirectoryOffsetField = interoperabilityDirectoryOffsetField;
+	//		this.interoperabilityDirectory = interoperabilityDirectory;
+	//	}
+
+}
\ No newline at end of file

Propchange: incubator/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffOutputSummary.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/ExifRewriteTest.java
URL: http://svn.apache.org/viewvc/incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/ExifRewriteTest.java?rev=609512&r1=609511&r2=609512&view=diff
==============================================================================
--- incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/ExifRewriteTest.java (original)
+++ incubator/sanselan/trunk/src/test/java/org/apache/sanselan/formats/jpeg/ExifRewriteTest.java Sun Jan  6 20:39:11 2008
@@ -20,6 +20,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Hashtable;
@@ -82,8 +83,15 @@
 		}
 	}
 
-	public void testRewrite() throws IOException, ImageReadException,
-			ImageWriteException
+	private interface Rewriter
+	{
+		public void rewrite(ByteSource byteSource, OutputStream os,
+				TiffOutputSet outputSet) throws ImageReadException,
+				IOException, ImageWriteException;
+	}
+
+	public void rewrite(Rewriter rewriter) throws IOException,
+			ImageReadException, ImageWriteException
 	{
 		List images = getImagesWithExifData();
 		for (int i = 0; i < images.size(); i++)
@@ -107,10 +115,10 @@
 			//			Photoshop photoshop = metadata.getPhotoshop();
 
 			TiffOutputSet outputSet = oldExifMetadata.getOutputSet();
-			outputSet.dump();
+//			outputSet.dump();
 
 			ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			new ExifRewriter().updateExifMetadata(byteSource, baos, outputSet);
+			rewriter.rewrite(byteSource, baos, outputSet);
 			byte bytes[] = baos.toByteArray();
 			File tempFile = File.createTempFile("test", ".jpg");
 			Debug.debug("tempFile", tempFile);
@@ -127,11 +135,45 @@
 			assertNotNull(newMetadata);
 			TiffImageMetadata newExifMetadata = newMetadata.getExif();
 			assertNotNull(newExifMetadata);
-			newMetadata.dump();
+//			newMetadata.dump();
 
 			compare(oldExifMetadata, newExifMetadata);
 		}
 	}
+
+	public void testRewriteLossy() throws IOException, ImageReadException,
+			ImageWriteException
+	{
+		Rewriter rewriter = new Rewriter()
+		{
+			public void rewrite(ByteSource byteSource, OutputStream os,
+					TiffOutputSet outputSet) throws ImageReadException,
+					IOException, ImageWriteException
+			{
+				new ExifRewriter().updateExifMetadataLossy(byteSource, os,
+						outputSet);
+			}
+		};
+
+		rewrite(rewriter);
+	}
+
+//	public void testRewriteLossless() throws IOException, ImageReadException,
+//			ImageWriteException
+//	{
+//		Rewriter rewriter = new Rewriter()
+//		{
+//			public void rewrite(ByteSource byteSource, OutputStream os,
+//					TiffOutputSet outputSet) throws ImageReadException,
+//					IOException, ImageWriteException
+//			{
+//				new ExifRewriter().updateExifMetadataLossless(byteSource, os,
+//						outputSet);
+//			}
+//		};
+//
+//		rewrite(rewriter);
+//	}
 
 	private Hashtable makeDirectoryMap(ArrayList directories)
 	{