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);
+ }
}