You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2010/09/10 18:33:42 UTC

svn commit: r995859 [25/30] - in /commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan: ./ color/ common/ common/byteSources/ common/mylzw/ formats/bmp/ formats/bmp/pixelparsers/ formats/bmp/writers/ formats/gif/ formats/ico/ formats/jpeg/ f...

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterCMYK.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterCMYK.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterCMYK.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterCMYK.java Fri Sep 10 16:33:35 2010
@@ -24,23 +24,23 @@ import org.apache.sanselan.color.ColorCo
 
 public class PhotometricInterpreterCMYK extends PhotometricInterpreter
 {
-	public PhotometricInterpreterCMYK(int fSamplesPerPixel,
-			int fBitsPerSample[], int Predictor, int width, int height)
-	{
-		super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
-	}
+    public PhotometricInterpreterCMYK(int fSamplesPerPixel,
+            int fBitsPerSample[], int Predictor, int width, int height)
+    {
+        super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
+    }
 
-	public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
-			throws ImageReadException, IOException
-	{
+    public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
+            throws ImageReadException, IOException
+    {
 
-		int sc = samples[0];
-		int sm = samples[1];
-		int sy = samples[2];
-		int sk = samples[3];
+        int sc = samples[0];
+        int sm = samples[1];
+        int sy = samples[2];
+        int sk = samples[3];
 
-		int rgb = ColorConversions.convertCMYKtoRGB(sc, sm, sy, sk);
-		bi.setRGB(x, y, rgb);
-	}
+        int rgb = ColorConversions.convertCMYKtoRGB(sc, sm, sy, sk);
+        bi.setRGB(x, y, rgb);
+    }
 
 }
\ No newline at end of file

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterLogLUV.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterLogLUV.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterLogLUV.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterLogLUV.java Fri Sep 10 16:33:35 2010
@@ -23,132 +23,132 @@ import org.apache.sanselan.ImageReadExce
 
 public class PhotometricInterpreterLogLUV extends PhotometricInterpreter
 {
-	//	private final boolean yOnly;
+    //    private final boolean yOnly;
 
-	public PhotometricInterpreterLogLUV(int fSamplesPerPixel,
-			int fBitsPerSample[], int Predictor, int width, int height,
-			boolean yonly)
-	{
-		super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
-
-		//		this.yOnly = yonly;
-	}
-
-	public void dumpstats() throws ImageReadException, IOException
-	{
-	}
-
-	private float cube(float f)
-	{
-		return f * f * f;
-	}
-
-	//		private float function_f(float value, )
-
-	public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
-			throws ImageReadException, IOException
-	{
-		float X, Y, Z;
-
-		int cieL = samples[0];
-		int cieA = (byte) samples[1];
-		int cieB = (byte) samples[2];
-
-		{
-
-			float var_Y = ((cieL * 100.0f / 255.0f) + 16.0f) / 116.0f;
-			float var_X = cieA / 500.0f + var_Y;
-			float var_Z = var_Y - cieB / 200.0f;
-
-			float var_x_cube = cube(var_X);
-			float var_y_cube = cube(var_Y);
-			float var_z_cube = cube(var_Z);
-
-			if (var_y_cube > 0.008856f)
-				var_Y = var_y_cube;
-			else
-				var_Y = (var_Y - 16 / 116.0f) / 7.787f;
-
-			if (var_x_cube > 0.008856f)
-				var_X = var_x_cube;
-			else
-				var_X = (var_X - 16 / 116.0f) / 7.787f;
-
-			if (var_z_cube > 0.008856f)
-				var_Z = var_z_cube;
-			else
-				var_Z = (var_Z - 16 / 116.0f) / 7.787f;
-
-			float ref_X = 95.047f;
-			float ref_Y = 100.000f;
-			float ref_Z = 108.883f;
-
-			X = ref_X * var_X; //ref_X =  95.047  Observer= 2°, Illuminant= D65
-			Y = ref_Y * var_Y; //ref_Y = 100.000
-			Z = ref_Z * var_Z; //ref_Z = 108.883
-
-		}
-
-		//			ref_X =  95.047        //Observer = 2°, Illuminant = D65
-		//			ref_Y = 100.000
-		//			ref_Z = 108.883
-
-		int R, G, B;
-		{
-			float var_X = X / 100f; //X = From 0 to ref_X
-			float var_Y = Y / 100f; //Y = From 0 to ref_Y
-			float var_Z = Z / 100f; //Z = From 0 to ref_Y
-
-			float var_R = var_X * 3.2406f + var_Y * -1.5372f + var_Z * -0.4986f;
-			float var_G = var_X * -0.9689f + var_Y * 1.8758f + var_Z * 0.0415f;
-			float var_B = var_X * 0.0557f + var_Y * -0.2040f + var_Z * 1.0570f;
-
-			if (var_R > 0.0031308)
-				var_R = 1.055f * (float) Math.pow(var_R, (1 / 2.4)) - 0.055f;
-			else
-				var_R = 12.92f * var_R;
-			if (var_G > 0.0031308)
-				var_G = 1.055f * (float) Math.pow(var_G, (1 / 2.4)) - 0.055f;
-			else
-				var_G = 12.92f * var_G;
-
-			if (var_B > 0.0031308)
-				var_B = 1.055f * (float) Math.pow(var_B, (1 / 2.4)) - 0.055f;
-			else
-				var_B = 12.92f * var_B;
-
-			//				var_R = (((var_R-)))
-			//				updateMaxMin(new float[]{
-			//						var_R, var_G, var_B,
-			//				}, maxVarRGB, minVarRGB);
-
-			//				var_R = ((var_R + 0.16561039f) / (3.0152583f + 0.16561039f));
-			//				var_G = ((var_G + 0.06561642f) / (3.0239854f + 0.06561642f));
-			//				var_B = ((var_B + 0.19393992f) / (3.1043448f + 0.19393992f));
-
-			R = (int) (var_R * 255f);
-			G = (int) (var_G * 255f);
-			B = (int) (var_B * 255f);
-		}
-
-		//			float R = 1.910f * X - 0.532f * Y - 0.288f * Z;
-		//			float G = -0.985f * X + 1.999f * Y - 0.028f * Z;
-		//			float B = 0.058f * X - 0.118f * Y + 0.898f * Z;
-
-		//			updateMaxMin(new float[]{
-		//					R, G, B,
-		//			}, maxRGB, minRGB);
-
-		int red = R;
-		int green = G;
-		int blue = B;
-
-		red = Math.min(255, Math.max(0, red));
-		green = Math.min(255, Math.max(0, green));
-		blue = Math.min(255, Math.max(0, blue));
-		int alpha = 0xff;
-		int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-		bi.setRGB(x, y, rgb);
+    public PhotometricInterpreterLogLUV(int fSamplesPerPixel,
+            int fBitsPerSample[], int Predictor, int width, int height,
+            boolean yonly)
+    {
+        super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
+
+        //        this.yOnly = yonly;
+    }
+
+    public void dumpstats() throws ImageReadException, IOException
+    {
+    }
+
+    private float cube(float f)
+    {
+        return f * f * f;
+    }
+
+    //        private float function_f(float value, )
+
+    public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
+            throws ImageReadException, IOException
+    {
+        float X, Y, Z;
+
+        int cieL = samples[0];
+        int cieA = (byte) samples[1];
+        int cieB = (byte) samples[2];
+
+        {
+
+            float var_Y = ((cieL * 100.0f / 255.0f) + 16.0f) / 116.0f;
+            float var_X = cieA / 500.0f + var_Y;
+            float var_Z = var_Y - cieB / 200.0f;
+
+            float var_x_cube = cube(var_X);
+            float var_y_cube = cube(var_Y);
+            float var_z_cube = cube(var_Z);
+
+            if (var_y_cube > 0.008856f)
+                var_Y = var_y_cube;
+            else
+                var_Y = (var_Y - 16 / 116.0f) / 7.787f;
+
+            if (var_x_cube > 0.008856f)
+                var_X = var_x_cube;
+            else
+                var_X = (var_X - 16 / 116.0f) / 7.787f;
+
+            if (var_z_cube > 0.008856f)
+                var_Z = var_z_cube;
+            else
+                var_Z = (var_Z - 16 / 116.0f) / 7.787f;
+
+            float ref_X = 95.047f;
+            float ref_Y = 100.000f;
+            float ref_Z = 108.883f;
+
+            X = ref_X * var_X; //ref_X =  95.047  Observer= 2°, Illuminant= D65
+            Y = ref_Y * var_Y; //ref_Y = 100.000
+            Z = ref_Z * var_Z; //ref_Z = 108.883
+
+        }
+
+        //            ref_X =  95.047        //Observer = 2°, Illuminant = D65
+        //            ref_Y = 100.000
+        //            ref_Z = 108.883
+
+        int R, G, B;
+        {
+            float var_X = X / 100f; //X = From 0 to ref_X
+            float var_Y = Y / 100f; //Y = From 0 to ref_Y
+            float var_Z = Z / 100f; //Z = From 0 to ref_Y
+
+            float var_R = var_X * 3.2406f + var_Y * -1.5372f + var_Z * -0.4986f;
+            float var_G = var_X * -0.9689f + var_Y * 1.8758f + var_Z * 0.0415f;
+            float var_B = var_X * 0.0557f + var_Y * -0.2040f + var_Z * 1.0570f;
+
+            if (var_R > 0.0031308)
+                var_R = 1.055f * (float) Math.pow(var_R, (1 / 2.4)) - 0.055f;
+            else
+                var_R = 12.92f * var_R;
+            if (var_G > 0.0031308)
+                var_G = 1.055f * (float) Math.pow(var_G, (1 / 2.4)) - 0.055f;
+            else
+                var_G = 12.92f * var_G;
+
+            if (var_B > 0.0031308)
+                var_B = 1.055f * (float) Math.pow(var_B, (1 / 2.4)) - 0.055f;
+            else
+                var_B = 12.92f * var_B;
+
+            //                var_R = (((var_R-)))
+            //                updateMaxMin(new float[]{
+            //                        var_R, var_G, var_B,
+            //                }, maxVarRGB, minVarRGB);
+
+            //                var_R = ((var_R + 0.16561039f) / (3.0152583f + 0.16561039f));
+            //                var_G = ((var_G + 0.06561642f) / (3.0239854f + 0.06561642f));
+            //                var_B = ((var_B + 0.19393992f) / (3.1043448f + 0.19393992f));
+
+            R = (int) (var_R * 255f);
+            G = (int) (var_G * 255f);
+            B = (int) (var_B * 255f);
+        }
+
+        //            float R = 1.910f * X - 0.532f * Y - 0.288f * Z;
+        //            float G = -0.985f * X + 1.999f * Y - 0.028f * Z;
+        //            float B = 0.058f * X - 0.118f * Y + 0.898f * Z;
+
+        //            updateMaxMin(new float[]{
+        //                    R, G, B,
+        //            }, maxRGB, minRGB);
+
+        int red = R;
+        int green = G;
+        int blue = B;
+
+        red = Math.min(255, Math.max(0, red));
+        green = Math.min(255, Math.max(0, green));
+        blue = Math.min(255, Math.max(0, blue));
+        int alpha = 0xff;
+        int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+        bi.setRGB(x, y, rgb);
 
-	}
+    }
 }
\ No newline at end of file

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterPalette.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterPalette.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterPalette.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterPalette.java Fri Sep 10 16:33:35 2010
@@ -23,32 +23,32 @@ import org.apache.sanselan.ImageReadExce
 
 public class PhotometricInterpreterPalette extends PhotometricInterpreter
 {
-	private final int[] fColorMap;
+    private final int[] fColorMap;
 
-	public PhotometricInterpreterPalette(int fSamplesPerPixel,
-			int fBitsPerSample[], int Predictor, int width, int height,
-			int[] fColorMap)
-	{
-		super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
-
-		this.fColorMap = fColorMap;
-	}
-
-	public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
-			throws ImageReadException, IOException
-	{
-		int fBitsPerPixel = bitsPerSample[0];
-		int colormap_scale = (1 << fBitsPerPixel);
-		//			int expected_colormap_size = 3 * (1 << fBitsPerPixel);
-
-		int index = samples[0];
-		int red = fColorMap[index] >> 8;
-		int green = fColorMap[index + (colormap_scale)] >> 8;
-		int blue = fColorMap[index + (2 * colormap_scale)] >> 8;
-
-		int alpha = 0xff;
-		int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-		bi.setRGB(x, y, rgb);
+    public PhotometricInterpreterPalette(int fSamplesPerPixel,
+            int fBitsPerSample[], int Predictor, int width, int height,
+            int[] fColorMap)
+    {
+        super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
+
+        this.fColorMap = fColorMap;
+    }
+
+    public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
+            throws ImageReadException, IOException
+    {
+        int fBitsPerPixel = bitsPerSample[0];
+        int colormap_scale = (1 << fBitsPerPixel);
+        //            int expected_colormap_size = 3 * (1 << fBitsPerPixel);
+
+        int index = samples[0];
+        int red = fColorMap[index] >> 8;
+        int green = fColorMap[index + (colormap_scale)] >> 8;
+        int blue = fColorMap[index + (2 * colormap_scale)] >> 8;
+
+        int alpha = 0xff;
+        int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+        bi.setRGB(x, y, rgb);
 
-	}
+    }
 }
\ No newline at end of file

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterRGB.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterRGB.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterRGB.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterRGB.java Fri Sep 10 16:33:35 2010
@@ -23,22 +23,22 @@ import org.apache.sanselan.ImageReadExce
 
 public class PhotometricInterpreterRGB extends PhotometricInterpreter
 {
-	public PhotometricInterpreterRGB(int fSamplesPerPixel,
-			int fBitsPerSample[], int Predictor, int width, int height)
-	{
-		super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
-	}
+    public PhotometricInterpreterRGB(int fSamplesPerPixel,
+            int fBitsPerSample[], int Predictor, int width, int height)
+    {
+        super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
+    }
 
-	public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
-			throws ImageReadException, IOException
-	{
-		int red = samples[0];
-		int green = samples[1];
-		int blue = samples[2];
+    public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
+            throws ImageReadException, IOException
+    {
+        int red = samples[0];
+        int green = samples[1];
+        int blue = samples[2];
 
-		int alpha = 0xff;
-		int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-		bi.setRGB(x, y, rgb);
+        int alpha = 0xff;
+        int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+        bi.setRGB(x, y, rgb);
 
-	}
+    }
 }
\ No newline at end of file

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterYCbCr.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterYCbCr.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterYCbCr.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/photometricinterpreters/PhotometricInterpreterYCbCr.java Fri Sep 10 16:33:35 2010
@@ -24,64 +24,64 @@ import org.apache.sanselan.ImageReadExce
 public class PhotometricInterpreterYCbCr extends PhotometricInterpreter
 {
 
-	public PhotometricInterpreterYCbCr(double[] fYCbCrCoefficients,
-			int[] fYCbCrPositioning, int[] fYCbCrSubSampling,
-			double[] fReferenceBlackWhite, int fSamplesPerPixel,
-			int fBitsPerSample[], int Predictor, int width, int height)
-	{
-		super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
-	}
-
-	public int limit(int value, int min, int max)
-	{
-		return Math.min(max, Math.max(min, value));
-	}
-
-	/**
-	 * This method converts a YUV (aka YCbCr) colorspace to a RGB colorspace.
-	 * This is handy when trying to reconstruct an image in Java from YCbCr transmitted
-	 * data. This routine expects the data to fall in the standard PC 0..255 range
-	 * per pixel, with the array dimensions corresponding to the imageWidth and imageHeight.
-	 * These variables are either set manually in the case of a null constructor,
-	 * or they are automatically calculated from the image parameter constructor.
-	 * @param Y The Y component set.
-	 * @param Cb The Cb component set.
-	 * @param Cr The Cr component set.
-	 * @return R The R component.
-	 */
-	public int convertYCbCrtoRGB(int Y, int Cb, int Cr)
-	{
-		double r1 = (((1.164 * (Y - 16.0))) + (1.596 * (Cr - 128.0)));
-		double g1 = (((1.164 * (Y - 16.0)))
-				- (0.813 * (Cr - 128.0)) - (0.392 * (Cb - 128.0)));
-		double b1 = (((1.164 * (Y - 16.0))) + (2.017 * (Cb - 128.0)));
-
-		int r = limit((int) r1, 0, 255);
-		int g = limit((int) g1, 0, 255);
-		int b = limit((int) b1, 0, 255);
-
-		int alpha = 0xff;
-		int rgb = (alpha << 24) | (r << 16) | (g << 8) | (b << 0);
-		return rgb;
-	}
-
-	public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
-			throws ImageReadException, IOException
-	{
-		int Y = samples[0];
-		int Cb = samples[1];
-		int Cr = samples[2];
-		double R = Y + 1.402 * (Cr - 128.0);
-		double G = Y - 0.34414 * (Cb - 128.0) - 0.71414 * (Cr - 128.0);
-		double B = Y + 1.772 * (Cb - 128.0);
-
-		int red = limit((int) R, 0, 255);
-		int green = limit((int) G, 0, 255);
-		int blue = limit((int) B, 0, 255);
-
-		int alpha = 0xff;
-		int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
-		bi.setRGB(x, y, rgb);
+    public PhotometricInterpreterYCbCr(double[] fYCbCrCoefficients,
+            int[] fYCbCrPositioning, int[] fYCbCrSubSampling,
+            double[] fReferenceBlackWhite, int fSamplesPerPixel,
+            int fBitsPerSample[], int Predictor, int width, int height)
+    {
+        super(fSamplesPerPixel, fBitsPerSample, Predictor, width, height);
+    }
+
+    public int limit(int value, int min, int max)
+    {
+        return Math.min(max, Math.max(min, value));
+    }
+
+    /**
+     * This method converts a YUV (aka YCbCr) colorspace to a RGB colorspace.
+     * This is handy when trying to reconstruct an image in Java from YCbCr transmitted
+     * data. This routine expects the data to fall in the standard PC 0..255 range
+     * per pixel, with the array dimensions corresponding to the imageWidth and imageHeight.
+     * These variables are either set manually in the case of a null constructor,
+     * or they are automatically calculated from the image parameter constructor.
+     * @param Y The Y component set.
+     * @param Cb The Cb component set.
+     * @param Cr The Cr component set.
+     * @return R The R component.
+     */
+    public int convertYCbCrtoRGB(int Y, int Cb, int Cr)
+    {
+        double r1 = (((1.164 * (Y - 16.0))) + (1.596 * (Cr - 128.0)));
+        double g1 = (((1.164 * (Y - 16.0)))
+                - (0.813 * (Cr - 128.0)) - (0.392 * (Cb - 128.0)));
+        double b1 = (((1.164 * (Y - 16.0))) + (2.017 * (Cb - 128.0)));
+
+        int r = limit((int) r1, 0, 255);
+        int g = limit((int) g1, 0, 255);
+        int b = limit((int) b1, 0, 255);
+
+        int alpha = 0xff;
+        int rgb = (alpha << 24) | (r << 16) | (g << 8) | (b << 0);
+        return rgb;
+    }
+
+    public void interpretPixel(BufferedImage bi, int samples[], int x, int y)
+            throws ImageReadException, IOException
+    {
+        int Y = samples[0];
+        int Cb = samples[1];
+        int Cr = samples[2];
+        double R = Y + 1.402 * (Cr - 128.0);
+        double G = Y - 0.34414 * (Cb - 128.0) - 0.71414 * (Cr - 128.0);
+        double B = Y + 1.772 * (Cb - 128.0);
+
+        int red = limit((int) R, 0, 255);
+        int green = limit((int) G, 0, 255);
+        int blue = limit((int) B, 0, 255);
+
+        int alpha = 0xff;
+        int rgb = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+        bi.setRGB(x, y, rgb);
 
-	}
+    }
 }
\ No newline at end of file

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/ImageDataOffsets.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/ImageDataOffsets.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/ImageDataOffsets.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/ImageDataOffsets.java Fri Sep 10 16:33:35 2010
@@ -20,25 +20,25 @@ import org.apache.sanselan.formats.tiff.
 
 class ImageDataOffsets
 {
-	public final int imageDataOffsets[];
-	public final TiffOutputField imageDataOffsetsField;
-	public final TiffOutputItem outputItems[];
+    public final int imageDataOffsets[];
+    public final TiffOutputField imageDataOffsetsField;
+    public final TiffOutputItem outputItems[];
 
-	public ImageDataOffsets(final TiffElement.DataElement imageData[],
-			final int[] imageDataOffsets,
-			final TiffOutputField imageDataOffsetsField)
-	{
-		this.imageDataOffsets = imageDataOffsets;
-		this.imageDataOffsetsField = imageDataOffsetsField;
+    public ImageDataOffsets(final TiffElement.DataElement imageData[],
+            final int[] imageDataOffsets,
+            final TiffOutputField imageDataOffsetsField)
+    {
+        this.imageDataOffsets = imageDataOffsets;
+        this.imageDataOffsetsField = imageDataOffsetsField;
 
-		outputItems = new TiffOutputItem[imageData.length];
-		for (int i = 0; i < imageData.length; i++)
-		{
-			TiffOutputItem item = new TiffOutputItem.Value("TIFF image data",
-					imageData[i].data);
-			outputItems[i] = item;
-		}
+        outputItems = new TiffOutputItem[imageData.length];
+        for (int i = 0; i < imageData.length; i++)
+        {
+            TiffOutputItem item = new TiffOutputItem.Value("TIFF image data",
+                    imageData[i].data);
+            outputItems[i] = item;
+        }
 
-	}
+    }
 
 }
\ No newline at end of file

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterBase.java Fri Sep 10 16:33:35 2010
@@ -36,519 +36,519 @@ import org.apache.sanselan.formats.tiff.
 import org.apache.sanselan.formats.tiff.constants.TiffConstants;
 
 public abstract class TiffImageWriterBase implements TiffConstants,
-		BinaryConstants
+        BinaryConstants
 {
 
-	protected final int byteOrder;
+    protected final int byteOrder;
 
-	public TiffImageWriterBase()
-	{
-		this.byteOrder = DEFAULT_TIFF_BYTE_ORDER;
-	}
-
-	public TiffImageWriterBase(int byteOrder)
-	{
-		this.byteOrder = byteOrder;
-	}
-
-	protected final static int imageDataPaddingLength(int dataLength)
-	{
-		return (4 - (dataLength % 4)) % 4;
-	}
-
-	public abstract void write(OutputStream os, TiffOutputSet outputSet)
-			throws IOException, ImageWriteException;
-
-	protected TiffOutputSummary validateDirectories(TiffOutputSet outputSet)
-			throws ImageWriteException
-	{
-		List directories = outputSet.getDirectories();
-
-		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)
-			}
-
-			HashSet fieldTags = new HashSet();
-			ArrayList fields = directory.getFields();
-			for (int j = 0; j < fields.size(); j++)
-			{
-				TiffOutputField field = (TiffOutputField) fields.get(j);
-
-				Integer fieldKey = new Integer(field.tag);
-				if (fieldTags.contains(fieldKey))
-					throw new ImageWriteException("Tag ("
-							+ field.tagInfo.getDescription()
-							+ ") appears twice in directory.");
-				fieldTags.add(fieldKey);
-
-				if (field.tag == EXIF_TAG_EXIF_OFFSET.tag)
-				{
-					if (exifDirectoryOffsetField != null)
-						throw new ImageWriteException(
-								"More than one Exif directory offset field.");
-					exifDirectoryOffsetField = field;
-				} else if (field.tag == EXIF_TAG_INTEROP_OFFSET.tag)
-				{
-					if (interoperabilityDirectoryOffsetField != null)
-						throw new ImageWriteException(
-								"More than one Interoperability directory offset field.");
-					interoperabilityDirectoryOffsetField = field;
-				} else if (field.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(byteOrder,
-				rootDirectory, directoryTypeMap);
-
-		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 (exifDirectory == null)
-			{
-				exifDirectory = outputSet.addExifDirectory();
-			}
-
-			if (interoperabilityDirectoryOffsetField == null)
-			{
-				interoperabilityDirectoryOffsetField = TiffOutputField
-						.createOffsetField(EXIF_TAG_INTEROP_OFFSET, byteOrder);
-				exifDirectory.add(interoperabilityDirectoryOffsetField);
-			}
-
-			result.add(interoperabilityDirectory,
-					interoperabilityDirectoryOffsetField);
-		}
-
-		// 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);
-		}
-
-		return result;
-
-		// Debug.debug();
-	}
-
-	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);
-
-		String xmpXml = null;
-		if (params.containsKey(PARAM_KEY_XMP_XML))
-		{
-			xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
-			params.remove(PARAM_KEY_XMP_XML);
-		}
-
-		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 LZW_MINIMUM_CODE_SIZE = 8;
-
-				MyLZWCompressor compressor = new MyLZWCompressor(
-						LZW_MINIMUM_CODE_SIZE, 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).");
-
-		TiffElement.DataElement imageData[] = new TiffElement.DataElement[strips.length];
-		for (int i = 0; i < strips.length; i++)
-			imageData[i] = new TiffImageData.Data(0, strips[i].length,
-					strips[i]);
-
-		// int stripOffsets[] = new int[stripCount];
-		// int stripByteCounts[] = new int[stripCount];
-		//
-		// for (int i = 0; i < strips.length; i++)
-		// stripByteCounts[i] = strips[i].length;
-
-		TiffOutputSet outputSet = new TiffOutputSet(byteOrder);
-		TiffOutputDirectory directory = outputSet.addRootDirectory();
-
-		// 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);
-			}
-
-			if (null != xmpXml)
-			{
-				byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
-
-				TiffOutputField field = new TiffOutputField(TIFF_TAG_XMP,
-						FIELD_TYPE_BYTE, xmpXmlBytes.length, xmpXmlBytes);
-				directory.add(field);
-			}
-
-		}
-
-		TiffImageData tiffImageData = new TiffImageData.Strips(imageData,
-				rowsPerStrip);
-		directory.setTiffImageData(tiffImageData);
-
-		write(os, outputSet);
-	}
-
-	private byte[][] getStrips(BufferedImage src, int samplesPerPixel,
-			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
-						* samplesPerPixel;
-				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;
-	}
-
-	protected void writeImageFileHeader(BinaryOutputStream bos)
-			throws IOException, ImageWriteException
-	{
-		int offsetToFirstIFD = TIFF_HEADER_SIZE;
-
-		writeImageFileHeader(bos, offsetToFirstIFD);
-	}
-
-	protected void writeImageFileHeader(BinaryOutputStream bos,
-			int offsetToFirstIFD) throws IOException, ImageWriteException
-	{
-		bos.write(byteOrder);
-		bos.write(byteOrder);
+    public TiffImageWriterBase()
+    {
+        this.byteOrder = DEFAULT_TIFF_BYTE_ORDER;
+    }
+
+    public TiffImageWriterBase(int byteOrder)
+    {
+        this.byteOrder = byteOrder;
+    }
+
+    protected final static int imageDataPaddingLength(int dataLength)
+    {
+        return (4 - (dataLength % 4)) % 4;
+    }
+
+    public abstract void write(OutputStream os, TiffOutputSet outputSet)
+            throws IOException, ImageWriteException;
+
+    protected TiffOutputSummary validateDirectories(TiffOutputSet outputSet)
+            throws ImageWriteException
+    {
+        List directories = outputSet.getDirectories();
+
+        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)
+            }
+
+            HashSet fieldTags = new HashSet();
+            ArrayList fields = directory.getFields();
+            for (int j = 0; j < fields.size(); j++)
+            {
+                TiffOutputField field = (TiffOutputField) fields.get(j);
+
+                Integer fieldKey = new Integer(field.tag);
+                if (fieldTags.contains(fieldKey))
+                    throw new ImageWriteException("Tag ("
+                            + field.tagInfo.getDescription()
+                            + ") appears twice in directory.");
+                fieldTags.add(fieldKey);
+
+                if (field.tag == EXIF_TAG_EXIF_OFFSET.tag)
+                {
+                    if (exifDirectoryOffsetField != null)
+                        throw new ImageWriteException(
+                                "More than one Exif directory offset field.");
+                    exifDirectoryOffsetField = field;
+                } else if (field.tag == EXIF_TAG_INTEROP_OFFSET.tag)
+                {
+                    if (interoperabilityDirectoryOffsetField != null)
+                        throw new ImageWriteException(
+                                "More than one Interoperability directory offset field.");
+                    interoperabilityDirectoryOffsetField = field;
+                } else if (field.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(byteOrder,
+                rootDirectory, directoryTypeMap);
+
+        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 (exifDirectory == null)
+            {
+                exifDirectory = outputSet.addExifDirectory();
+            }
+
+            if (interoperabilityDirectoryOffsetField == null)
+            {
+                interoperabilityDirectoryOffsetField = TiffOutputField
+                        .createOffsetField(EXIF_TAG_INTEROP_OFFSET, byteOrder);
+                exifDirectory.add(interoperabilityDirectoryOffsetField);
+            }
+
+            result.add(interoperabilityDirectory,
+                    interoperabilityDirectoryOffsetField);
+        }
+
+        // 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);
+        }
+
+        return result;
+
+        // Debug.debug();
+    }
+
+    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);
+
+        String xmpXml = null;
+        if (params.containsKey(PARAM_KEY_XMP_XML))
+        {
+            xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
+            params.remove(PARAM_KEY_XMP_XML);
+        }
+
+        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 LZW_MINIMUM_CODE_SIZE = 8;
+
+                MyLZWCompressor compressor = new MyLZWCompressor(
+                        LZW_MINIMUM_CODE_SIZE, 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).");
+
+        TiffElement.DataElement imageData[] = new TiffElement.DataElement[strips.length];
+        for (int i = 0; i < strips.length; i++)
+            imageData[i] = new TiffImageData.Data(0, strips[i].length,
+                    strips[i]);
+
+        // int stripOffsets[] = new int[stripCount];
+        // int stripByteCounts[] = new int[stripCount];
+        //
+        // for (int i = 0; i < strips.length; i++)
+        // stripByteCounts[i] = strips[i].length;
+
+        TiffOutputSet outputSet = new TiffOutputSet(byteOrder);
+        TiffOutputDirectory directory = outputSet.addRootDirectory();
+
+        // 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);
+            }
+
+            if (null != xmpXml)
+            {
+                byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
+
+                TiffOutputField field = new TiffOutputField(TIFF_TAG_XMP,
+                        FIELD_TYPE_BYTE, xmpXmlBytes.length, xmpXmlBytes);
+                directory.add(field);
+            }
+
+        }
+
+        TiffImageData tiffImageData = new TiffImageData.Strips(imageData,
+                rowsPerStrip);
+        directory.setTiffImageData(tiffImageData);
+
+        write(os, outputSet);
+    }
+
+    private byte[][] getStrips(BufferedImage src, int samplesPerPixel,
+            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
+                        * samplesPerPixel;
+                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;
+    }
+
+    protected void writeImageFileHeader(BinaryOutputStream bos)
+            throws IOException, ImageWriteException
+    {
+        int offsetToFirstIFD = TIFF_HEADER_SIZE;
+
+        writeImageFileHeader(bos, offsetToFirstIFD);
+    }
+
+    protected void writeImageFileHeader(BinaryOutputStream bos,
+            int offsetToFirstIFD) throws IOException, ImageWriteException
+    {
+        bos.write(byteOrder);
+        bos.write(byteOrder);
 
-		bos.write2Bytes(42); // tiffVersion
+        bos.write2Bytes(42); // tiffVersion
 
-		bos.write4Bytes(offsetToFirstIFD);
-	}
+        bos.write4Bytes(offsetToFirstIFD);
+    }
 
 }

Modified: commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java
URL: http://svn.apache.org/viewvc/commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java?rev=995859&r1=995858&r2=995859&view=diff
==============================================================================
--- commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java (original)
+++ commons/proper/sanselan/trunk/src/main/java/org/apache/sanselan/formats/tiff/write/TiffImageWriterLossless.java Fri Sep 10 16:33:35 2010
@@ -42,407 +42,407 @@ import org.apache.sanselan.util.Debug;
 
 public class TiffImageWriterLossless extends TiffImageWriterBase
 {
-	private final byte exifBytes[];
+    private final byte exifBytes[];
 
-	public TiffImageWriterLossless(byte exifBytes[])
-	{
-		this.exifBytes = exifBytes;
-	}
-
-	public TiffImageWriterLossless(int byteOrder, byte exifBytes[])
-	{
-		super(byteOrder);
-		this.exifBytes = exifBytes;
-	}
-
-	//	private static class TiffPiece
-	//	{
-	//		public final int offset;
-	//		public final int length;
-	//
-	//		public TiffPiece(final int offset, final int length)
-	//		{
-	//			this.offset = offset;
-	//			this.length = length;
-	//		}
-	//	}
-
-	private void dumpElements(List elements) throws IOException
-	{
-		//		try
-		//		{
-		ByteSource byteSource = new ByteSourceArray(exifBytes);
-
-		dumpElements(byteSource, elements);
-		//		}
-		//		catch (ImageReadException e)
-		//		{
-		//			throw new ImageWriteException(e.getMessage(), e);
-		//		}
-	}
-
-	private void dumpElements(ByteSource byteSource, List elements)
-			throws IOException
-	{
-		int last = TIFF_HEADER_SIZE;
-		for (int i = 0; i < elements.size(); i++)
-		{
-			TiffElement element = (TiffElement) elements.get(i);
-			if (element.offset > last)
-			{
-				final int SLICE_SIZE = 32;
-				int gepLength = element.offset - last;
-				Debug.debug("gap of " + gepLength + " bytes.");
-				byte bytes[] = byteSource.getBlock(last, gepLength);
-				if (bytes.length > 2 * SLICE_SIZE)
-				{
-					Debug.debug("\t" + "head", BinaryFileFunctions.head(bytes,
-							SLICE_SIZE));
-					Debug.debug("\t" + "tail", BinaryFileFunctions.tail(bytes,
-							SLICE_SIZE));
-				}
-				else
-					Debug.debug("\t" + "bytes", bytes);
-			}
-
-			Debug.debug("element[" + i + "]:" + element.getElementDescription()
-					+ " (" + element.offset + " + " + element.length + " = "
-					+ (element.offset + element.length) + ")");
-			if (element instanceof TiffDirectory)
-			{
-				TiffDirectory dir = (TiffDirectory) element;
-				Debug.debug("\t" + "next Directory Offset: "
-						+ dir.nextDirectoryOffset);
-			}
-			last = element.offset + element.length;
-		}
-		Debug.debug();
-	}
-
-	private List analyzeOldTiff() throws ImageWriteException, IOException
-	{
-		try
-		{
-			ByteSource byteSource = new ByteSourceArray(exifBytes);
-			Map params = null;
-			FormatCompliance formatCompliance = FormatCompliance.getDefault();
-			TiffContents contents = new TiffReader(false).readContents(byteSource,
-					params, formatCompliance);
-
-			ArrayList elements = new ArrayList();
-			//			result.add(contents.header); // ?
-
-			List directories = contents.directories;
-			for (int d = 0; d < directories.size(); d++)
-			{
-				TiffDirectory directory = (TiffDirectory) directories.get(d);
-				elements.add(directory);
-
-				List fields = directory.getDirectoryEntrys();
-				for (int f = 0; f < fields.size(); f++)
-				{
-					TiffField field = (TiffField) fields.get(f);
-					TiffElement oversizeValue = field.getOversizeValueElement();
-					if (oversizeValue != null)
-						elements.add(oversizeValue);
-
-				}
-
-				JpegImageData jpegImageData = directory.getJpegImageData();
-				if (jpegImageData != null)
-					elements.add(jpegImageData);
-
-				TiffImageData tiffImageData = directory.getTiffImageData();
-				if (tiffImageData != null)
-				{
-					TiffElement.DataElement data[] = tiffImageData
-							.getImageData();
-					for (int i = 0; i < data.length; i++)
-						elements.add(data[i]);
-				}
-			}
-
-			Collections.sort(elements, TiffElement.COMPARATOR);
-
-			//			dumpElements(byteSource, elements);
-
-			List result = new ArrayList();
-			{
-				final int TOLERANCE = 3;
-				//				int last = TIFF_HEADER_SIZE;
-				TiffElement start = null;
-				int index = -1;
-				for (int i = 0; i < elements.size(); i++)
-				{
-					TiffElement element = (TiffElement) elements.get(i);
-					int lastElementByte = element.offset + element.length;
-					if (start == null)
-					{
-						start = element;
-						index = lastElementByte;
-					}
-					else if (element.offset - index > TOLERANCE)
-					{
-						result.add(new TiffElement.Stub(start.offset, index
-								- start.offset));
-						start = element;
-						index = lastElementByte;
-					}
-					else
-					{
-						index = lastElementByte;
-					}
-				}
-				if (null != start)
-					result.add(new TiffElement.Stub(start.offset, index
-							- start.offset));
-			}
-
-			//			dumpElements(byteSource, result);
-
-			return result;
-		}
-		catch (ImageReadException e)
-		{
-			throw new ImageWriteException(e.getMessage(), e);
-		}
-	}
-
-	public void write(OutputStream os, TiffOutputSet outputSet)
-			throws IOException, ImageWriteException
-	{
-		List analysis = analyzeOldTiff();
-		int oldLength = exifBytes.length;
-		if (analysis.size() < 1)
-			throw new ImageWriteException("Couldn't analyze old tiff data.");
-		else if (analysis.size() == 1)
-		{
-			TiffElement onlyElement = (TiffElement) analysis.get(0);
-			//			Debug.debug("onlyElement", onlyElement.getElementDescription());
-			if (onlyElement.offset == TIFF_HEADER_SIZE
-					&& onlyElement.offset + onlyElement.length
-							+ TIFF_HEADER_SIZE == oldLength)
-			{
-				// no gaps in old data, safe to complete overwrite.
-				new TiffImageWriterLossy(byteOrder).write(os, outputSet);
-				return;
-			}
-		}
-
-		//		if (true)
-		//			throw new ImageWriteException("hahah");
-
-		//		List directories = outputSet.getDirectories();
-
-		TiffOutputSummary outputSummary = validateDirectories(outputSet);
-
-		List outputItems = outputSet.getOutputItems(outputSummary);
-
-		int outputLength = updateOffsetsStep(analysis, outputItems);
-		//		Debug.debug("outputLength", outputLength);
-
-		outputSummary.updateOffsets(byteOrder);
-
-		writeStep(os, outputSet, analysis, outputItems, outputLength);
-
-	}
-
-	private static final Comparator ELEMENT_SIZE_COMPARATOR = new Comparator()
-	{
-		public int compare(Object o1, Object o2)
-		{
-			TiffElement e1 = (TiffElement) o1;
-			TiffElement e2 = (TiffElement) o2;
-			return e1.length - e2.length;
-		}
-	};
-
-	private static final Comparator ITEM_SIZE_COMPARATOR = new Comparator()
-	{
-		public int compare(Object o1, Object o2)
-		{
-			TiffOutputItem e1 = (TiffOutputItem) o1;
-			TiffOutputItem e2 = (TiffOutputItem) o2;
-			return e1.getItemLength() - e2.getItemLength();
-		}
-	};
-
-	private int updateOffsetsStep(List analysis, List outputItems)
-			throws IOException, ImageWriteException
-	{
-		// items we cannot fit into a gap, we shall append to tail.
-		int overflowIndex = exifBytes.length;
-
-		// make copy.
-		List unusedElements = new ArrayList(analysis);
-
-		// should already be in order of offset, but make sure.
-		Collections.sort(unusedElements, TiffElement.COMPARATOR);
-		Collections.reverse(unusedElements);
-		// any items that represent a gap at the end of the exif segment, can be discarded.
-		while (unusedElements.size() > 0)
-		{
-			TiffElement element = (TiffElement) unusedElements.get(0);
-			int elementEnd = element.offset + element.length;
-			if (elementEnd == overflowIndex)
-			{
-				// discarding a tail element.  should only happen once.
-				overflowIndex -= element.length;
-				unusedElements.remove(0);
-			}
-			else
-				break;
-		}
-
-		Collections.sort(unusedElements, ELEMENT_SIZE_COMPARATOR);
-		Collections.reverse(unusedElements);
-
-		//		Debug.debug("unusedElements");
-		//		dumpElements(unusedElements);
-
-		// make copy.
-		List unplacedItems = new ArrayList(outputItems);
-		Collections.sort(unplacedItems, ITEM_SIZE_COMPARATOR);
-		Collections.reverse(unplacedItems);
-
-		while (unplacedItems.size() > 0)
-		{
-			// pop off largest unplaced item.
-			TiffOutputItem outputItem = (TiffOutputItem) unplacedItems
-					.remove(0);
-			int outputItemLength = outputItem.getItemLength();
-			//			Debug.debug("largest unplaced item: "
-			//					+ outputItem.getItemDescription() + " (" + outputItemLength
-			//					+ ")");
-
-			// search for the smallest possible element large enough to hold the item.
-			TiffElement bestFit = null;
-			for (int i = 0; i < unusedElements.size(); i++)
-			{
-				TiffElement element = (TiffElement) unusedElements.get(i);
-				if (element.length >= outputItemLength)
-					bestFit = element;
-				else
-					break;
-			}
-			if (null == bestFit)
-			{
-				// we couldn't place this item.  overflow.
-				outputItem.setOffset(overflowIndex);
-				overflowIndex += outputItemLength;
-			}
-			else
-			{
-				outputItem.setOffset(bestFit.offset);
-				unusedElements.remove(bestFit);
-
-				if (bestFit.length > outputItemLength)
-				{
-					// not a perfect fit.
-					int excessOffset = bestFit.offset + outputItemLength;
-					int excessLength = bestFit.length - outputItemLength;
-					unusedElements.add(new TiffElement.Stub(excessOffset,
-							excessLength));
-					// make sure the new element is in the correct order.
-					Collections.sort(unusedElements, ELEMENT_SIZE_COMPARATOR);
-					Collections.reverse(unusedElements);
-				}
-			}
-		}
-
-		return overflowIndex;
-		//
-		//		if (true)
-		//			throw new IOException("mew");
-		//
-		//		//		int offset = TIFF_HEADER_SIZE;
-		//		int offset = exifBytes.length;
-		//
-		//		for (int i = 0; i < outputItems.size(); i++)
-		//		{
-		//			TiffOutputItem outputItem = (TiffOutputItem) outputItems.get(i);
-		//
-		//			outputItem.setOffset(offset);
-		//			int itemLength = outputItem.getItemLength();
-		//			offset += itemLength;
-		//
-		//			int remainder = imageDataPaddingLength(itemLength);
-		//			offset += remainder;
-		//		}
-	}
-	private static class BufferOutputStream extends OutputStream
-	{
-		private final byte buffer[];
-		private int index;
-
-		public BufferOutputStream(final byte[] buffer, final int index)
-		{
-			this.buffer = buffer;
-			this.index = index;
-		}
-
-		public void write(int b) throws IOException
-		{
-			if (index >= buffer.length)
-				throw new IOException("Buffer overflow.");
-
-			buffer[index++] = (byte) b;
-		}
-
-		public void write(byte b[], int off, int len) throws IOException
-		{
-			if (index + len > buffer.length)
-				throw new IOException("Buffer overflow.");
-			System.arraycopy(b, off, buffer, index, len);
-			index += len;
-		}
-	}
-
-	private void writeStep(OutputStream os, TiffOutputSet outputSet,
-			List analysis, List outputItems, int outputLength)
-			throws IOException, ImageWriteException
-	{
-		TiffOutputDirectory rootDirectory = outputSet.getRootDirectory();
-
-		byte output[] = new byte[outputLength];
-
-		// copy old data (including maker notes, etc.)
-		System.arraycopy(exifBytes, 0, output, 0, Math.min(exifBytes.length,
-				output.length));
-
-		//		bos.write(exifBytes, TIFF_HEADER_SIZE, exifBytes.length
-		//		- TIFF_HEADER_SIZE);
-
-		{
-			BufferOutputStream tos = new BufferOutputStream(output, 0);
-			BinaryOutputStream bos = new BinaryOutputStream(tos, byteOrder);
-			writeImageFileHeader(bos, rootDirectory.getOffset());
-		}
-
-		// zero out the parsed pieces of old exif segment, in case we don't overwrite them.
-		for (int i = 0; i < analysis.size(); i++)
-		{
-			TiffElement element = (TiffElement) analysis.get(i);
-			for (int j = 0; j < element.length; j++)
-			{
-				int index = element.offset + j;
-				if (index < output.length)
-					output[index] = 0;
-			}
-		}
-
-		// write in the new items
-		for (int i = 0; i < outputItems.size(); i++)
-		{
-			TiffOutputItem outputItem = (TiffOutputItem) outputItems.get(i);
-
-			BufferOutputStream tos = new BufferOutputStream(output, outputItem
-					.getOffset());
-			BinaryOutputStream bos = new BinaryOutputStream(tos, byteOrder);
-			outputItem.writeItem(bos);
-		}
+    public TiffImageWriterLossless(byte exifBytes[])
+    {
+        this.exifBytes = exifBytes;
+    }
+
+    public TiffImageWriterLossless(int byteOrder, byte exifBytes[])
+    {
+        super(byteOrder);
+        this.exifBytes = exifBytes;
+    }
+
+    //    private static class TiffPiece
+    //    {
+    //        public final int offset;
+    //        public final int length;
+    //
+    //        public TiffPiece(final int offset, final int length)
+    //        {
+    //            this.offset = offset;
+    //            this.length = length;
+    //        }
+    //    }
+
+    private void dumpElements(List elements) throws IOException
+    {
+        //        try
+        //        {
+        ByteSource byteSource = new ByteSourceArray(exifBytes);
+
+        dumpElements(byteSource, elements);
+        //        }
+        //        catch (ImageReadException e)
+        //        {
+        //            throw new ImageWriteException(e.getMessage(), e);
+        //        }
+    }
+
+    private void dumpElements(ByteSource byteSource, List elements)
+            throws IOException
+    {
+        int last = TIFF_HEADER_SIZE;
+        for (int i = 0; i < elements.size(); i++)
+        {
+            TiffElement element = (TiffElement) elements.get(i);
+            if (element.offset > last)
+            {
+                final int SLICE_SIZE = 32;
+                int gepLength = element.offset - last;
+                Debug.debug("gap of " + gepLength + " bytes.");
+                byte bytes[] = byteSource.getBlock(last, gepLength);
+                if (bytes.length > 2 * SLICE_SIZE)
+                {
+                    Debug.debug("\t" + "head", BinaryFileFunctions.head(bytes,
+                            SLICE_SIZE));
+                    Debug.debug("\t" + "tail", BinaryFileFunctions.tail(bytes,
+                            SLICE_SIZE));
+                }
+                else
+                    Debug.debug("\t" + "bytes", bytes);
+            }
+
+            Debug.debug("element[" + i + "]:" + element.getElementDescription()
+                    + " (" + element.offset + " + " + element.length + " = "
+                    + (element.offset + element.length) + ")");
+            if (element instanceof TiffDirectory)
+            {
+                TiffDirectory dir = (TiffDirectory) element;
+                Debug.debug("\t" + "next Directory Offset: "
+                        + dir.nextDirectoryOffset);
+            }
+            last = element.offset + element.length;
+        }
+        Debug.debug();
+    }
+
+    private List analyzeOldTiff() throws ImageWriteException, IOException
+    {
+        try
+        {
+            ByteSource byteSource = new ByteSourceArray(exifBytes);
+            Map params = null;
+            FormatCompliance formatCompliance = FormatCompliance.getDefault();
+            TiffContents contents = new TiffReader(false).readContents(byteSource,
+                    params, formatCompliance);
+
+            ArrayList elements = new ArrayList();
+            //            result.add(contents.header); // ?
+
+            List directories = contents.directories;
+            for (int d = 0; d < directories.size(); d++)
+            {
+                TiffDirectory directory = (TiffDirectory) directories.get(d);
+                elements.add(directory);
+
+                List fields = directory.getDirectoryEntrys();
+                for (int f = 0; f < fields.size(); f++)
+                {
+                    TiffField field = (TiffField) fields.get(f);
+                    TiffElement oversizeValue = field.getOversizeValueElement();
+                    if (oversizeValue != null)
+                        elements.add(oversizeValue);
+
+                }
+
+                JpegImageData jpegImageData = directory.getJpegImageData();
+                if (jpegImageData != null)
+                    elements.add(jpegImageData);
+
+                TiffImageData tiffImageData = directory.getTiffImageData();
+                if (tiffImageData != null)
+                {
+                    TiffElement.DataElement data[] = tiffImageData
+                            .getImageData();
+                    for (int i = 0; i < data.length; i++)
+                        elements.add(data[i]);
+                }
+            }
+
+            Collections.sort(elements, TiffElement.COMPARATOR);
+
+            //            dumpElements(byteSource, elements);
+
+            List result = new ArrayList();
+            {
+                final int TOLERANCE = 3;
+                //                int last = TIFF_HEADER_SIZE;
+                TiffElement start = null;
+                int index = -1;
+                for (int i = 0; i < elements.size(); i++)
+                {
+                    TiffElement element = (TiffElement) elements.get(i);
+                    int lastElementByte = element.offset + element.length;
+                    if (start == null)
+                    {
+                        start = element;
+                        index = lastElementByte;
+                    }
+                    else if (element.offset - index > TOLERANCE)
+                    {
+                        result.add(new TiffElement.Stub(start.offset, index
+                                - start.offset));
+                        start = element;
+                        index = lastElementByte;
+                    }
+                    else
+                    {
+                        index = lastElementByte;
+                    }
+                }
+                if (null != start)
+                    result.add(new TiffElement.Stub(start.offset, index
+                            - start.offset));
+            }
+
+            //            dumpElements(byteSource, result);
+
+            return result;
+        }
+        catch (ImageReadException e)
+        {
+            throw new ImageWriteException(e.getMessage(), e);
+        }
+    }
+
+    public void write(OutputStream os, TiffOutputSet outputSet)
+            throws IOException, ImageWriteException
+    {
+        List analysis = analyzeOldTiff();
+        int oldLength = exifBytes.length;
+        if (analysis.size() < 1)
+            throw new ImageWriteException("Couldn't analyze old tiff data.");
+        else if (analysis.size() == 1)
+        {
+            TiffElement onlyElement = (TiffElement) analysis.get(0);
+            //            Debug.debug("onlyElement", onlyElement.getElementDescription());
+            if (onlyElement.offset == TIFF_HEADER_SIZE
+                    && onlyElement.offset + onlyElement.length
+                            + TIFF_HEADER_SIZE == oldLength)
+            {
+                // no gaps in old data, safe to complete overwrite.
+                new TiffImageWriterLossy(byteOrder).write(os, outputSet);
+                return;
+            }
+        }
+
+        //        if (true)
+        //            throw new ImageWriteException("hahah");
+
+        //        List directories = outputSet.getDirectories();
+
+        TiffOutputSummary outputSummary = validateDirectories(outputSet);
+
+        List outputItems = outputSet.getOutputItems(outputSummary);
+
+        int outputLength = updateOffsetsStep(analysis, outputItems);
+        //        Debug.debug("outputLength", outputLength);
+
+        outputSummary.updateOffsets(byteOrder);
+
+        writeStep(os, outputSet, analysis, outputItems, outputLength);
+
+    }
+
+    private static final Comparator ELEMENT_SIZE_COMPARATOR = new Comparator()
+    {
+        public int compare(Object o1, Object o2)
+        {
+            TiffElement e1 = (TiffElement) o1;
+            TiffElement e2 = (TiffElement) o2;
+            return e1.length - e2.length;
+        }
+    };
+
+    private static final Comparator ITEM_SIZE_COMPARATOR = new Comparator()
+    {
+        public int compare(Object o1, Object o2)
+        {
+            TiffOutputItem e1 = (TiffOutputItem) o1;
+            TiffOutputItem e2 = (TiffOutputItem) o2;
+            return e1.getItemLength() - e2.getItemLength();
+        }
+    };
+
+    private int updateOffsetsStep(List analysis, List outputItems)
+            throws IOException, ImageWriteException
+    {
+        // items we cannot fit into a gap, we shall append to tail.
+        int overflowIndex = exifBytes.length;
+
+        // make copy.
+        List unusedElements = new ArrayList(analysis);
+
+        // should already be in order of offset, but make sure.
+        Collections.sort(unusedElements, TiffElement.COMPARATOR);
+        Collections.reverse(unusedElements);
+        // any items that represent a gap at the end of the exif segment, can be discarded.
+        while (unusedElements.size() > 0)
+        {
+            TiffElement element = (TiffElement) unusedElements.get(0);
+            int elementEnd = element.offset + element.length;
+            if (elementEnd == overflowIndex)
+            {
+                // discarding a tail element.  should only happen once.
+                overflowIndex -= element.length;
+                unusedElements.remove(0);
+            }
+            else
+                break;
+        }
+
+        Collections.sort(unusedElements, ELEMENT_SIZE_COMPARATOR);
+        Collections.reverse(unusedElements);
+
+        //        Debug.debug("unusedElements");
+        //        dumpElements(unusedElements);
+
+        // make copy.
+        List unplacedItems = new ArrayList(outputItems);
+        Collections.sort(unplacedItems, ITEM_SIZE_COMPARATOR);
+        Collections.reverse(unplacedItems);
+
+        while (unplacedItems.size() > 0)
+        {
+            // pop off largest unplaced item.
+            TiffOutputItem outputItem = (TiffOutputItem) unplacedItems
+                    .remove(0);
+            int outputItemLength = outputItem.getItemLength();
+            //            Debug.debug("largest unplaced item: "
+            //                    + outputItem.getItemDescription() + " (" + outputItemLength
+            //                    + ")");
+
+            // search for the smallest possible element large enough to hold the item.
+            TiffElement bestFit = null;
+            for (int i = 0; i < unusedElements.size(); i++)
+            {
+                TiffElement element = (TiffElement) unusedElements.get(i);
+                if (element.length >= outputItemLength)
+                    bestFit = element;
+                else
+                    break;
+            }
+            if (null == bestFit)
+            {
+                // we couldn't place this item.  overflow.
+                outputItem.setOffset(overflowIndex);
+                overflowIndex += outputItemLength;
+            }
+            else
+            {
+                outputItem.setOffset(bestFit.offset);
+                unusedElements.remove(bestFit);
+
+                if (bestFit.length > outputItemLength)
+                {
+                    // not a perfect fit.
+                    int excessOffset = bestFit.offset + outputItemLength;
+                    int excessLength = bestFit.length - outputItemLength;
+                    unusedElements.add(new TiffElement.Stub(excessOffset,
+                            excessLength));
+                    // make sure the new element is in the correct order.
+                    Collections.sort(unusedElements, ELEMENT_SIZE_COMPARATOR);
+                    Collections.reverse(unusedElements);
+                }
+            }
+        }
+
+        return overflowIndex;
+        //
+        //        if (true)
+        //            throw new IOException("mew");
+        //
+        //        //        int offset = TIFF_HEADER_SIZE;
+        //        int offset = exifBytes.length;
+        //
+        //        for (int i = 0; i < outputItems.size(); i++)
+        //        {
+        //            TiffOutputItem outputItem = (TiffOutputItem) outputItems.get(i);
+        //
+        //            outputItem.setOffset(offset);
+        //            int itemLength = outputItem.getItemLength();
+        //            offset += itemLength;
+        //
+        //            int remainder = imageDataPaddingLength(itemLength);
+        //            offset += remainder;
+        //        }
+    }
+    private static class BufferOutputStream extends OutputStream
+    {
+        private final byte buffer[];
+        private int index;
+
+        public BufferOutputStream(final byte[] buffer, final int index)
+        {
+            this.buffer = buffer;
+            this.index = index;
+        }
+
+        public void write(int b) throws IOException
+        {
+            if (index >= buffer.length)
+                throw new IOException("Buffer overflow.");
+
+            buffer[index++] = (byte) b;
+        }
+
+        public void write(byte b[], int off, int len) throws IOException
+        {
+            if (index + len > buffer.length)
+                throw new IOException("Buffer overflow.");
+            System.arraycopy(b, off, buffer, index, len);
+            index += len;
+        }
+    }
+
+    private void writeStep(OutputStream os, TiffOutputSet outputSet,
+            List analysis, List outputItems, int outputLength)
+            throws IOException, ImageWriteException
+    {
+        TiffOutputDirectory rootDirectory = outputSet.getRootDirectory();
+
+        byte output[] = new byte[outputLength];
+
+        // copy old data (including maker notes, etc.)
+        System.arraycopy(exifBytes, 0, output, 0, Math.min(exifBytes.length,
+                output.length));
+
+        //        bos.write(exifBytes, TIFF_HEADER_SIZE, exifBytes.length
+        //        - TIFF_HEADER_SIZE);
+
+        {
+            BufferOutputStream tos = new BufferOutputStream(output, 0);
+            BinaryOutputStream bos = new BinaryOutputStream(tos, byteOrder);
+            writeImageFileHeader(bos, rootDirectory.getOffset());
+        }
+
+        // zero out the parsed pieces of old exif segment, in case we don't overwrite them.
+        for (int i = 0; i < analysis.size(); i++)
+        {
+            TiffElement element = (TiffElement) analysis.get(i);
+            for (int j = 0; j < element.length; j++)
+            {
+                int index = element.offset + j;
+                if (index < output.length)
+                    output[index] = 0;
+            }
+        }
+
+        // write in the new items
+        for (int i = 0; i < outputItems.size(); i++)
+        {
+            TiffOutputItem outputItem = (TiffOutputItem) outputItems.get(i);
+
+            BufferOutputStream tos = new BufferOutputStream(output, outputItem
+                    .getOffset());
+            BinaryOutputStream bos = new BinaryOutputStream(tos, byteOrder);
+            outputItem.writeItem(bos);
+        }
 
-		os.write(output);
-	}
+        os.write(output);
+    }
 
 }