You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cf...@apache.org on 2012/10/25 21:01:49 UTC
svn commit: r1402274 [18/31] - in
/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext:
./ awt/ awt/color/ awt/font/ awt/g2d/ awt/geom/ awt/image/ awt/image/codec/
awt/image/codec/jpeg/ awt/image/codec/p...
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,1724 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.codec.tiff;
+
+import java.awt.Rectangle;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.IndexColorModel;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.List;
+import java.util.zip.Deflater;
+
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.ImageEncodeParam;
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.ImageEncoderImpl;
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.SeekableOutputStream;
+
+import com.sun.image.codec.jpeg.JPEGEncodeParam;
+import com.sun.image.codec.jpeg.JPEGQTable;
+
+/**
+ * A baseline TIFF writer. The writer outputs TIFF images in either Bilevel,
+ * Greyscale, Palette color or Full Color modes.
+ *
+ * @version $Id: TIFFImageEncoder.java 498740 2007-01-22 18:35:57Z dvholten $
+ */
+public class TIFFImageEncoder extends ImageEncoderImpl {
+
+ // Image Types
+ private static final int TIFF_UNSUPPORTED = -1;
+ private static final int TIFF_BILEVEL_WHITE_IS_ZERO = 0;
+ private static final int TIFF_BILEVEL_BLACK_IS_ZERO = 1;
+ private static final int TIFF_GRAY = 2;
+ private static final int TIFF_PALETTE = 3;
+ private static final int TIFF_RGB = 4;
+ private static final int TIFF_CMYK = 5;
+ private static final int TIFF_YCBCR = 6;
+ private static final int TIFF_CIELAB = 7;
+ private static final int TIFF_GENERIC = 8;
+
+ // Compression types
+ private static final int COMP_NONE = 1;
+ private static final int COMP_JPEG_TTN2 = 7;
+ private static final int COMP_PACKBITS = 32773;
+ private static final int COMP_DEFLATE = 32946;
+
+ // Incidental tags
+ private static final int TIFF_JPEG_TABLES = 347;
+ private static final int TIFF_YCBCR_SUBSAMPLING = 530;
+ private static final int TIFF_YCBCR_POSITIONING = 531;
+ private static final int TIFF_REF_BLACK_WHITE = 532;
+
+ // ExtraSamples types
+ private static final int EXTRA_SAMPLE_UNSPECIFIED = 0;
+ private static final int EXTRA_SAMPLE_ASSOCIATED_ALPHA = 1;
+ private static final int EXTRA_SAMPLE_UNASSOCIATED_ALPHA = 2;
+
+ // Default values
+ private static final int DEFAULT_ROWS_PER_STRIP = 8;
+
+ public TIFFImageEncoder(OutputStream output, ImageEncodeParam param) {
+ super(output, param);
+ if (this.param == null) {
+ this.param = new TIFFEncodeParam();
+ }
+ }
+
+ /**
+ * Encodes a RenderedImage and writes the output to the
+ * OutputStream associated with this ImageEncoder.
+ */
+ public void encode(RenderedImage im) throws IOException {
+ // Write the file header (8 bytes).
+ writeFileHeader();
+
+ // Get the encoding parameters.
+ TIFFEncodeParam encodeParam = (TIFFEncodeParam)param;
+
+ Iterator iter = encodeParam.getExtraImages();
+ if(iter != null) {
+ int ifdOffset = 8;
+ RenderedImage nextImage = im;
+ TIFFEncodeParam nextParam = encodeParam;
+ boolean hasNext;
+ do {
+ hasNext = iter.hasNext();
+ ifdOffset = encode(nextImage, nextParam, ifdOffset, !hasNext);
+ if(hasNext) {
+ Object obj = iter.next();
+ if(obj instanceof RenderedImage) {
+ nextImage = (RenderedImage)obj;
+ nextParam = encodeParam;
+ } else if(obj instanceof Object[]) {
+ Object[] o = (Object[])obj;
+ nextImage = (RenderedImage)o[0];
+ nextParam = (TIFFEncodeParam)o[1];
+ }
+ }
+ } while(hasNext);
+ } else {
+ encode(im, encodeParam, 8, true);
+ }
+ }
+
+ private int encode(RenderedImage im, TIFFEncodeParam encodeParam,
+ int ifdOffset, boolean isLast) throws IOException {
+ // Currently all images are stored uncompressed.
+ int compression = encodeParam.getCompression();
+
+ // Get tiled output preference.
+ boolean isTiled = encodeParam.getWriteTiled();
+
+ // Set bounds.
+ int minX = im.getMinX();
+ int minY = im.getMinY();
+ int width = im.getWidth();
+ int height = im.getHeight();
+
+ // Get SampleModel.
+ SampleModel sampleModel = im.getSampleModel();
+
+ // Retrieve and verify sample size.
+ int[] sampleSize = sampleModel.getSampleSize();
+ for(int i = 1; i < sampleSize.length; i++) {
+ if(sampleSize[i] != sampleSize[0]) {
+ throw new Error("TIFFImageEncoder0");
+ }
+ }
+
+ // Check low bit limits.
+ int numBands = sampleModel.getNumBands();
+ if((sampleSize[0] == 1 || sampleSize[0] == 4) && numBands != 1) {
+ throw new Error("TIFFImageEncoder1");
+ }
+
+ // Retrieve and verify data type.
+ int dataType = sampleModel.getDataType();
+ switch(dataType) {
+ case DataBuffer.TYPE_BYTE:
+ if(sampleSize[0] != 1 && sampleSize[0] == 4 && // todo does this make sense??
+ sampleSize[0] != 8) { // we get error only for 4
+ throw new Error("TIFFImageEncoder2");
+ }
+ break;
+ case DataBuffer.TYPE_SHORT:
+ case DataBuffer.TYPE_USHORT:
+ if(sampleSize[0] != 16) {
+ throw new Error("TIFFImageEncoder3");
+ }
+ break;
+ case DataBuffer.TYPE_INT:
+ case DataBuffer.TYPE_FLOAT:
+ if(sampleSize[0] != 32) {
+ throw new Error("TIFFImageEncoder4");
+ }
+ break;
+ default:
+ throw new Error("TIFFImageEncoder5");
+ }
+
+ boolean dataTypeIsShort =
+ dataType == DataBuffer.TYPE_SHORT ||
+ dataType == DataBuffer.TYPE_USHORT;
+
+ ColorModel colorModel = im.getColorModel();
+ if (colorModel != null &&
+ colorModel instanceof IndexColorModel &&
+ dataType != DataBuffer.TYPE_BYTE) {
+ // Don't support (unsigned) short palette-color images.
+ throw new Error("TIFFImageEncoder6");
+ }
+ IndexColorModel icm = null;
+ int sizeOfColormap = 0;
+ char[] colormap = null;
+
+ // Set image type.
+ int imageType = TIFF_UNSUPPORTED;
+ int numExtraSamples = 0;
+ int extraSampleType = EXTRA_SAMPLE_UNSPECIFIED;
+ if(colorModel instanceof IndexColorModel) { // Bilevel or palette
+ icm = (IndexColorModel)colorModel;
+ int mapSize = icm.getMapSize();
+
+ if(sampleSize[0] == 1 && numBands == 1) { // Bilevel image
+
+ if (mapSize != 2) {
+ throw new IllegalArgumentException(
+ "TIFFImageEncoder7");
+ }
+
+ byte[] r = new byte[mapSize];
+ icm.getReds(r);
+ byte[] g = new byte[mapSize];
+ icm.getGreens(g);
+ byte[] b = new byte[mapSize];
+ icm.getBlues(b);
+
+ if ((r[0] & 0xff) == 0 &&
+ (r[1] & 0xff) == 255 &&
+ (g[0] & 0xff) == 0 &&
+ (g[1] & 0xff) == 255 &&
+ (b[0] & 0xff) == 0 &&
+ (b[1] & 0xff) == 255) {
+
+ imageType = TIFF_BILEVEL_BLACK_IS_ZERO;
+
+ } else if ((r[0] & 0xff) == 255 &&
+ (r[1] & 0xff) == 0 &&
+ (g[0] & 0xff) == 255 &&
+ (g[1] & 0xff) == 0 &&
+ (b[0] & 0xff) == 255 &&
+ (b[1] & 0xff) == 0) {
+
+ imageType = TIFF_BILEVEL_WHITE_IS_ZERO;
+
+ } else {
+ imageType = TIFF_PALETTE;
+ }
+
+ } else if(numBands == 1) { // Non-bilevel image.
+ // Palette color image.
+ imageType = TIFF_PALETTE;
+ }
+ } else if(colorModel == null) {
+
+ if(sampleSize[0] == 1 && numBands == 1) { // bilevel
+ imageType = TIFF_BILEVEL_BLACK_IS_ZERO;
+ } else { // generic image
+ imageType = TIFF_GENERIC;
+ if(numBands > 1) {
+ numExtraSamples = numBands - 1;
+ }
+ }
+
+ } else { // colorModel is non-null but not an IndexColorModel
+ ColorSpace colorSpace = colorModel.getColorSpace();
+
+ switch(colorSpace.getType()) {
+ case ColorSpace.TYPE_CMYK:
+ imageType = TIFF_CMYK;
+ break;
+ case ColorSpace.TYPE_GRAY:
+ imageType = TIFF_GRAY;
+ break;
+ case ColorSpace.TYPE_Lab:
+ imageType = TIFF_CIELAB;
+ break;
+ case ColorSpace.TYPE_RGB:
+ if(compression == COMP_JPEG_TTN2 &&
+ encodeParam.getJPEGCompressRGBToYCbCr()) {
+ imageType = TIFF_YCBCR;
+ } else {
+ imageType = TIFF_RGB;
+ }
+ break;
+ case ColorSpace.TYPE_YCbCr:
+ imageType = TIFF_YCBCR;
+ break;
+ default:
+ imageType = TIFF_GENERIC; // generic
+ break;
+ }
+
+ if(imageType == TIFF_GENERIC) {
+ numExtraSamples = numBands - 1;
+ } else if(numBands > 1) {
+ numExtraSamples = numBands - colorSpace.getNumComponents();
+ }
+
+ if(numExtraSamples == 1 && colorModel.hasAlpha()) {
+ extraSampleType = colorModel.isAlphaPremultiplied() ?
+ EXTRA_SAMPLE_ASSOCIATED_ALPHA :
+ EXTRA_SAMPLE_UNASSOCIATED_ALPHA;
+ }
+ }
+
+ if(imageType == TIFF_UNSUPPORTED) {
+ throw new Error("TIFFImageEncoder8");
+ }
+
+ // Check JPEG compatibility.
+ if(compression == COMP_JPEG_TTN2) {
+ if(imageType == TIFF_PALETTE) {
+ throw new Error("TIFFImageEncoder11");
+ } else if(!(sampleSize[0] == 8 &&
+ (imageType == TIFF_GRAY ||
+ imageType == TIFF_RGB ||
+ imageType == TIFF_YCBCR))) {
+ throw new Error("TIFFImageEncoder9");
+ }
+ }
+
+ int photometricInterpretation = -1;
+ switch (imageType) {
+
+ case TIFF_BILEVEL_WHITE_IS_ZERO:
+ photometricInterpretation = 0;
+ break;
+
+ case TIFF_BILEVEL_BLACK_IS_ZERO:
+ photometricInterpretation = 1;
+ break;
+
+ case TIFF_GRAY:
+ case TIFF_GENERIC:
+ // Since the CS_GRAY colorspace is always of type black_is_zero
+ photometricInterpretation = 1;
+ break;
+
+ case TIFF_PALETTE:
+ photometricInterpretation = 3;
+
+ icm = (IndexColorModel)colorModel;
+ sizeOfColormap = icm.getMapSize();
+
+ byte[] r = new byte[sizeOfColormap];
+ icm.getReds(r);
+ byte[] g = new byte[sizeOfColormap];
+ icm.getGreens(g);
+ byte[] b = new byte[sizeOfColormap];
+ icm.getBlues(b);
+
+ int redIndex = 0, greenIndex = sizeOfColormap;
+ int blueIndex = 2 * sizeOfColormap;
+ colormap = new char[sizeOfColormap * 3];
+ for (int i=0; i<sizeOfColormap; i++) {
+ int tmp = 0xff & r[i]; // beware of sign extended bytes
+ colormap[redIndex++] = (char)(( tmp << 8) | tmp );
+ tmp = 0xff & g[i];
+ colormap[greenIndex++] = (char)(( tmp << 8) | tmp );
+ tmp = 0xff & b[i];
+ colormap[blueIndex++] = (char)(( tmp << 8) | tmp );
+ }
+
+ sizeOfColormap *= 3;
+
+ break;
+
+ case TIFF_RGB:
+ photometricInterpretation = 2;
+ break;
+
+ case TIFF_CMYK:
+ photometricInterpretation = 5;
+ break;
+
+ case TIFF_YCBCR:
+ photometricInterpretation = 6;
+ break;
+
+ case TIFF_CIELAB:
+ photometricInterpretation = 8;
+ break;
+
+ default:
+ throw new Error("TIFFImageEncoder8");
+ }
+
+ // Initialize tile dimensions.
+ int tileWidth;
+ int tileHeight;
+ if(isTiled) {
+ tileWidth = encodeParam.getTileWidth() > 0 ?
+ encodeParam.getTileWidth() : im.getTileWidth();
+ tileHeight = encodeParam.getTileHeight() > 0 ?
+ encodeParam.getTileHeight() : im.getTileHeight();
+ } else {
+ tileWidth = width;
+
+ tileHeight = encodeParam.getTileHeight() > 0 ?
+ encodeParam.getTileHeight() : DEFAULT_ROWS_PER_STRIP;
+ }
+
+ // Re-tile for JPEG conformance if needed.
+ JPEGEncodeParam jep = null;
+ if(compression == COMP_JPEG_TTN2) {
+ // Get JPEGEncodeParam from encodeParam.
+ jep = encodeParam.getJPEGEncodeParam();
+
+ // Determine maximum subsampling.
+ int maxSubH = jep.getHorizontalSubsampling(0);
+ int maxSubV = jep.getVerticalSubsampling(0);
+ for(int i = 1; i < numBands; i++) {
+ int subH = jep.getHorizontalSubsampling(i);
+ if(subH > maxSubH) {
+ maxSubH = subH;
+ }
+ int subV = jep.getVerticalSubsampling(i);
+ if(subV > maxSubV) {
+ maxSubV = subV;
+ }
+ }
+
+ int factorV = 8*maxSubV;
+ tileHeight =
+ (int)((float)tileHeight/(float)factorV + 0.5F)*factorV;
+ if(tileHeight < factorV) {
+ tileHeight = factorV;
+ }
+
+ if(isTiled) {
+ int factorH = 8*maxSubH;
+ tileWidth =
+ (int)((float)tileWidth/(float)factorH + 0.5F)*factorH;
+ if(tileWidth < factorH) {
+ tileWidth = factorH;
+ }
+ }
+ }
+
+ int numTiles;
+ if(isTiled) {
+ // NB: Parentheses are used in this statement for correct rounding.
+ numTiles =
+ ((width + tileWidth - 1)/tileWidth) *
+ ((height + tileHeight - 1)/tileHeight);
+ } else {
+ numTiles = (int)Math.ceil((double)height/(double)tileHeight);
+ }
+
+ long[] tileByteCounts = new long[numTiles];
+
+ long bytesPerRow =
+ (long)Math.ceil((sampleSize[0] / 8.0) * tileWidth * numBands);
+
+ long bytesPerTile = bytesPerRow * tileHeight;
+
+ for (int i=0; i<numTiles; i++) {
+ tileByteCounts[i] = bytesPerTile;
+ }
+
+ if(!isTiled) {
+ // Last strip may have lesser rows
+ long lastStripRows = height - (tileHeight * (numTiles-1));
+ tileByteCounts[numTiles-1] = lastStripRows * bytesPerRow;
+ }
+
+ long totalBytesOfData = bytesPerTile * (numTiles - 1) +
+ tileByteCounts[numTiles-1];
+
+ // The data will be written after the IFD: create the array here
+ // but fill it in later.
+ long[] tileOffsets = new long[numTiles];
+
+ // Basic fields - have to be in increasing numerical order.
+ // ImageWidth 256
+ // ImageLength 257
+ // BitsPerSample 258
+ // Compression 259
+ // PhotoMetricInterpretation 262
+ // StripOffsets 273
+ // RowsPerStrip 278
+ // StripByteCounts 279
+ // XResolution 282
+ // YResolution 283
+ // ResolutionUnit 296
+
+ // Create Directory
+ SortedSet fields = new TreeSet();
+
+ // Image Width
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_IMAGE_WIDTH,
+ TIFFField.TIFF_LONG, 1,
+ new long[] {width}));
+
+ // Image Length
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_IMAGE_LENGTH,
+ TIFFField.TIFF_LONG, 1,
+ new long[] {height}));
+
+ char [] shortSampleSize = new char[numBands];
+ for (int i=0; i<numBands; i++)
+ shortSampleSize[i] = (char)sampleSize[i];
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE,
+ TIFFField.TIFF_SHORT, numBands,
+ shortSampleSize));
+
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_COMPRESSION,
+ TIFFField.TIFF_SHORT, 1,
+ new char[] {(char)compression}));
+
+ fields.add(
+ new TIFFField(TIFFImageDecoder.TIFF_PHOTOMETRIC_INTERPRETATION,
+ TIFFField.TIFF_SHORT, 1,
+ new char[] {(char)photometricInterpretation}));
+
+ if(!isTiled) {
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_STRIP_OFFSETS,
+ TIFFField.TIFF_LONG, numTiles,
+ tileOffsets));
+ }
+
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_SAMPLES_PER_PIXEL,
+ TIFFField.TIFF_SHORT, 1,
+ new char[] {(char)numBands}));
+
+ if(!isTiled) {
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP,
+ TIFFField.TIFF_LONG, 1,
+ new long[] {tileHeight}));
+
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS,
+ TIFFField.TIFF_LONG, numTiles,
+ tileByteCounts));
+ }
+
+ if (colormap != null) {
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_COLORMAP,
+ TIFFField.TIFF_SHORT, sizeOfColormap,
+ colormap));
+ }
+
+ if(isTiled) {
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_WIDTH,
+ TIFFField.TIFF_LONG, 1,
+ new long[] {tileWidth}));
+
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_LENGTH,
+ TIFFField.TIFF_LONG, 1,
+ new long[] {tileHeight}));
+
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_OFFSETS,
+ TIFFField.TIFF_LONG, numTiles,
+ tileOffsets));
+
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_BYTE_COUNTS,
+ TIFFField.TIFF_LONG, numTiles,
+ tileByteCounts));
+ }
+
+ if(numExtraSamples > 0) {
+ char[] extraSamples = new char[numExtraSamples];
+ for(int i = 0; i < numExtraSamples; i++) {
+ extraSamples[i] = (char)extraSampleType;
+ }
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_EXTRA_SAMPLES,
+ TIFFField.TIFF_SHORT, numExtraSamples,
+ extraSamples));
+ }
+
+ // Data Sample Format Extension fields.
+ if(dataType != DataBuffer.TYPE_BYTE) {
+ // SampleFormat
+ char[] sampleFormat = new char[numBands];
+ if(dataType == DataBuffer.TYPE_FLOAT) {
+ sampleFormat[0] = 3;
+ } else if(dataType == DataBuffer.TYPE_USHORT) {
+ sampleFormat[0] = 1;
+ } else {
+ sampleFormat[0] = 2;
+ }
+ for(int b = 1; b < numBands; b++) {
+ sampleFormat[b] = sampleFormat[0];
+ }
+ fields.add(new TIFFField(TIFFImageDecoder.TIFF_SAMPLE_FORMAT,
+ TIFFField.TIFF_SHORT, numBands,
+ sampleFormat));
+
+ // NOTE: We don't bother setting the SMinSampleValue and
+ // SMaxSampleValue fields as these both default to the
+ // extrema of the respective data types. Probably we should
+ // check for the presence of the "extrema" property and
+ // use it if available.
+ }
+
+ // Initialize some JPEG variables.
+ com.sun.image.codec.jpeg.JPEGEncodeParam jpegEncodeParam = null;
+ com.sun.image.codec.jpeg.JPEGImageEncoder jpegEncoder = null;
+ int jpegColorID = 0;
+
+ if(compression == COMP_JPEG_TTN2) {
+
+ // Initialize JPEG color ID.
+ jpegColorID =
+ com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_UNKNOWN;
+ switch(imageType) {
+ case TIFF_GRAY:
+ case TIFF_PALETTE:
+ jpegColorID =
+ com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_GRAY;
+ break;
+ case TIFF_RGB:
+ jpegColorID =
+ com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_RGB;
+ break;
+ case TIFF_YCBCR:
+ jpegColorID =
+ com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_YCbCr;
+ break;
+ }
+
+ // Get the JDK encoding parameters.
+ Raster tile00 = im.getTile(0, 0);
+ jpegEncodeParam =
+ com.sun.image.codec.jpeg.JPEGCodec.getDefaultJPEGEncodeParam(
+ tile00, jpegColorID);
+
+ modifyEncodeParam(jep, jpegEncodeParam, numBands);
+
+ // Write an abbreviated tables-only stream to JPEGTables field.
+ jpegEncodeParam.setImageInfoValid(false);
+ jpegEncodeParam.setTableInfoValid(true);
+ ByteArrayOutputStream tableStream =
+ new ByteArrayOutputStream();
+ jpegEncoder =
+ com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(
+ tableStream,
+ jpegEncodeParam);
+ jpegEncoder.encode(tile00);
+ byte[] tableData = tableStream.toByteArray();
+ fields.add(new TIFFField(TIFF_JPEG_TABLES,
+ TIFFField.TIFF_UNDEFINED,
+ tableData.length,
+ tableData));
+
+ // Reset encoder so it's recreated below.
+ jpegEncoder = null;
+ }
+
+ if(imageType == TIFF_YCBCR) {
+ // YCbCrSubSampling: 2 is the default so we must write 1 as
+ // we do not (yet) do any subsampling.
+ char subsampleH = 1;
+ char subsampleV = 1;
+
+ // If JPEG, update values.
+ if(compression == COMP_JPEG_TTN2) {
+ // Determine maximum subsampling.
+ subsampleH = (char)jep.getHorizontalSubsampling(0);
+ subsampleV = (char)jep.getVerticalSubsampling(0);
+ for(int i = 1; i < numBands; i++) {
+ char subH = (char)jep.getHorizontalSubsampling(i);
+ if(subH > subsampleH) {
+ subsampleH = subH;
+ }
+ char subV = (char)jep.getVerticalSubsampling(i);
+ if(subV > subsampleV) {
+ subsampleV = subV;
+ }
+ }
+ }
+
+ fields.add(new TIFFField(TIFF_YCBCR_SUBSAMPLING,
+ TIFFField.TIFF_SHORT, 2,
+ new char[] {subsampleH, subsampleV}));
+
+
+ // YCbCr positioning.
+ fields.add(new TIFFField(TIFF_YCBCR_POSITIONING,
+ TIFFField.TIFF_SHORT, 1,
+ new char[]
+ {(char)((compression == COMP_JPEG_TTN2)? 1 : 2)}));
+
+ // Reference black/white.
+ long[][] refbw;
+ if(compression == COMP_JPEG_TTN2) {
+ refbw =
+ new long[][] { // no headroon/footroom
+ {0, 1}, {255, 1}, {128, 1}, {255, 1}, {128, 1}, {255, 1}
+ };
+ } else {
+ refbw =
+ new long[][] { // CCIR 601.1 headroom/footroom (presumptive)
+ {15, 1}, {235, 1}, {128, 1}, {240, 1}, {128, 1}, {240, 1}
+ };
+ }
+ fields.add(new TIFFField(TIFF_REF_BLACK_WHITE,
+ TIFFField.TIFF_RATIONAL, 6,
+ refbw));
+ }
+
+ // ---- No more automatically generated fields should be added
+ // after this point. ----
+
+ // Add extra fields specified via the encoding parameters.
+ TIFFField[] extraFields = encodeParam.getExtraFields();
+ if(extraFields != null) {
+ List extantTags = new ArrayList(fields.size());
+ Iterator fieldIter = fields.iterator();
+ while(fieldIter.hasNext()) {
+ TIFFField fld = (TIFFField)fieldIter.next();
+ extantTags.add(new Integer(fld.getTag()));
+ }
+
+ int numExtraFields = extraFields.length;
+ for(int i = 0; i < numExtraFields; i++) {
+ TIFFField fld = extraFields[i];
+ Integer tagValue = new Integer(fld.getTag());
+ if(!extantTags.contains(tagValue)) {
+ fields.add(fld);
+ extantTags.add(tagValue);
+ }
+ }
+ }
+
+ // ---- No more fields of any type should be added after this. ----
+
+ // Determine the size of the IFD which is written after the header
+ // of the stream or after the data of the previous image in a
+ // multi-page stream.
+ int dirSize = getDirectorySize(fields);
+
+ // The first data segment is written after the field overflow
+ // following the IFD so initialize the first offset accordingly.
+ tileOffsets[0] = ifdOffset + dirSize;
+
+ // Branch here depending on whether data are being comrpressed.
+ // If not, then the IFD is written immediately.
+ // If so then there are three possibilities:
+ // A) the OutputStream is a SeekableOutputStream (outCache null);
+ // B) the OutputStream is not a SeekableOutputStream and a file cache
+ // is used (outCache non-null, tempFile non-null);
+ // C) the OutputStream is not a SeekableOutputStream and a memory cache
+ // is used (outCache non-null, tempFile null).
+
+ OutputStream outCache = null;
+ byte[] compressBuf = null;
+ File tempFile = null;
+
+ int nextIFDOffset = 0;
+ boolean skipByte = false;
+
+ Deflater deflater = null;
+ boolean jpegRGBToYCbCr = false;
+
+ if(compression == COMP_NONE) {
+ // Determine the number of bytes of padding necessary between
+ // the end of the IFD and the first data segment such that the
+ // alignment of the data conforms to the specification (required
+ // for uncompressed data only).
+ int numBytesPadding = 0;
+ if(sampleSize[0] == 16 && tileOffsets[0] % 2 != 0) {
+ numBytesPadding = 1;
+ tileOffsets[0]++;
+ } else if(sampleSize[0] == 32 && tileOffsets[0] % 4 != 0) {
+ numBytesPadding = (int)(4 - tileOffsets[0] % 4);
+ tileOffsets[0] += numBytesPadding;
+ }
+
+ // Update the data offsets (which TIFFField stores by reference).
+ for (int i = 1; i < numTiles; i++) {
+ tileOffsets[i] = tileOffsets[i-1] + tileByteCounts[i-1];
+ }
+
+ if(!isLast) {
+ // Determine the offset of the next IFD.
+ nextIFDOffset = (int)(tileOffsets[0] + totalBytesOfData);
+
+ // IFD offsets must be on a word boundary.
+ if ((nextIFDOffset&0x01) != 0) {
+ nextIFDOffset++;
+ skipByte = true;
+ }
+ }
+
+ // Write the IFD and field overflow before the image data.
+ writeDirectory(ifdOffset, fields, nextIFDOffset);
+
+ // Write any padding bytes needed between the end of the IFD
+ // and the start of the actual image data.
+ if(numBytesPadding != 0) {
+ for(int padding = 0; padding < numBytesPadding; padding++) {
+ output.write((byte)0);
+ }
+ }
+ } else {
+ // If compressing, the cannot be written yet as the size of the
+ // data segments is unknown.
+
+ if( output instanceof SeekableOutputStream ) {
+ // Simply seek to the first data segment position.
+ ((SeekableOutputStream)output).seek(tileOffsets[0]);
+ } else {
+ // Cache the original OutputStream.
+ outCache = output;
+
+ try {
+ // Attempt to create a temporary file.
+ tempFile = File.createTempFile("jai-SOS-", ".tmp");
+ tempFile.deleteOnExit();
+ RandomAccessFile raFile =
+ new RandomAccessFile(tempFile, "rw");
+ output = new SeekableOutputStream(raFile);
+
+ // this method is exited!
+ } catch(Exception e) {
+ // Allocate memory for the entire image data (!).
+ output = new ByteArrayOutputStream((int)totalBytesOfData);
+ }
+ }
+
+ int bufSize = 0;
+ switch(compression) {
+ case COMP_PACKBITS:
+ bufSize = (int)(bytesPerTile +
+ ((bytesPerRow+127)/128)*tileHeight);
+ break;
+ case COMP_JPEG_TTN2:
+ bufSize = 0;
+
+ // Set color conversion flag.
+ if(imageType == TIFF_YCBCR &&
+ colorModel != null &&
+ colorModel.getColorSpace().getType() ==
+ ColorSpace.TYPE_RGB) {
+ jpegRGBToYCbCr = true;
+ }
+ break;
+ case COMP_DEFLATE:
+ bufSize = (int)bytesPerTile;
+ deflater = new Deflater(encodeParam.getDeflateLevel());
+ break;
+ default:
+ bufSize = 0;
+ }
+ if(bufSize != 0) {
+ compressBuf = new byte[bufSize];
+ }
+ }
+
+ // ---- Writing of actual image data ----
+
+ // Buffer for up to tileHeight rows of pixels
+ int[] pixels = null;
+ float[] fpixels = null;
+
+ // Whether to test for contiguous data.
+ boolean checkContiguous =
+ ((sampleSize[0] == 1 &&
+ sampleModel instanceof MultiPixelPackedSampleModel &&
+ dataType == DataBuffer.TYPE_BYTE) ||
+ (sampleSize[0] == 8 &&
+ sampleModel instanceof ComponentSampleModel));
+
+ // Also create a buffer to hold tileHeight lines of the
+ // data to be written to the file, so we can use array writes.
+ byte[] bpixels = null;
+ if(compression != COMP_JPEG_TTN2) {
+ if(dataType == DataBuffer.TYPE_BYTE) {
+ bpixels = new byte[tileHeight * tileWidth * numBands];
+ } else if(dataTypeIsShort) {
+ bpixels = new byte[2 * tileHeight * tileWidth * numBands];
+ } else if(dataType == DataBuffer.TYPE_INT ||
+ dataType == DataBuffer.TYPE_FLOAT) {
+ bpixels = new byte[4 * tileHeight * tileWidth * numBands];
+ }
+ }
+
+ // Process tileHeight rows at a time
+ int lastRow = minY + height;
+ int lastCol = minX + width;
+ int tileNum = 0;
+ for (int row = minY; row < lastRow; row += tileHeight) {
+ int rows = isTiled ?
+ tileHeight : Math.min(tileHeight, lastRow - row);
+ int size = rows * tileWidth * numBands;
+
+ for(int col = minX; col < lastCol; col += tileWidth) {
+ // Grab the pixels
+ Raster src =
+ im.getData(new Rectangle(col, row, tileWidth, rows));
+
+ boolean useDataBuffer = false;
+ if(compression != COMP_JPEG_TTN2) { // JPEG access Raster
+ if(checkContiguous) {
+ if(sampleSize[0] == 8) { // 8-bit
+ ComponentSampleModel csm =
+ (ComponentSampleModel)src.getSampleModel();
+ int[] bankIndices = csm.getBankIndices();
+ int[] bandOffsets = csm.getBandOffsets();
+ int pixelStride = csm.getPixelStride();
+ int lineStride = csm.getScanlineStride();
+
+ if(pixelStride != numBands ||
+ lineStride != bytesPerRow) {
+ useDataBuffer = false;
+ } else {
+ useDataBuffer = true;
+ for(int i = 0;
+ useDataBuffer && i < numBands;
+ i++) {
+ if(bankIndices[i] != 0 ||
+ bandOffsets[i] != i) {
+ useDataBuffer = false;
+ }
+ }
+ }
+ } else { // 1-bit
+ MultiPixelPackedSampleModel mpp =
+ (MultiPixelPackedSampleModel)src.getSampleModel();
+ if(mpp.getNumBands() == 1 &&
+ mpp.getDataBitOffset() == 0 &&
+ mpp.getPixelBitStride() == 1) {
+ useDataBuffer = true;
+ }
+ }
+ }
+
+ if(!useDataBuffer) {
+ if(dataType == DataBuffer.TYPE_FLOAT) {
+ fpixels = src.getPixels(col, row, tileWidth, rows,
+ fpixels);
+ } else {
+ pixels = src.getPixels(col, row, tileWidth, rows,
+ pixels);
+ }
+ }
+ }
+
+ int index;
+
+ int pixel = 0;
+ int k = 0;
+ switch(sampleSize[0]) {
+
+ case 1:
+
+ if(useDataBuffer) {
+ byte[] btmp =
+ ((DataBufferByte)src.getDataBuffer()).getData();
+ MultiPixelPackedSampleModel mpp =
+ (MultiPixelPackedSampleModel)src.getSampleModel();
+ int lineStride = mpp.getScanlineStride();
+ int inOffset =
+ mpp.getOffset(col -
+ src.getSampleModelTranslateX(),
+ row -
+ src.getSampleModelTranslateY());
+ if(lineStride == (int)bytesPerRow) {
+ System.arraycopy(btmp, inOffset,
+ bpixels, 0,
+ (int)bytesPerRow*rows);
+ } else {
+ int outOffset = 0;
+ for(int j = 0; j < rows; j++) {
+ System.arraycopy(btmp, inOffset,
+ bpixels, outOffset,
+ (int)bytesPerRow);
+ inOffset += lineStride;
+ outOffset += (int)bytesPerRow;
+ }
+ }
+ } else {
+ index = 0;
+
+ // For each of the rows in a strip
+ for (int i=0; i<rows; i++) {
+
+ // Write number of pixels exactly divisible by 8
+ for (int j=0; j<tileWidth/8; j++) {
+
+ pixel =
+ (pixels[index++] << 7) |
+ (pixels[index++] << 6) |
+ (pixels[index++] << 5) |
+ (pixels[index++] << 4) |
+ (pixels[index++] << 3) |
+ (pixels[index++] << 2) |
+ (pixels[index++] << 1) |
+ pixels[index++];
+ bpixels[k++] = (byte)pixel;
+ }
+
+ // Write the pixels remaining after division by 8
+ if (tileWidth%8 > 0) {
+ pixel = 0;
+ for (int j=0; j<tileWidth%8; j++) {
+ pixel |= (pixels[index++] << (7 - j));
+ }
+ bpixels[k++] = (byte)pixel;
+ }
+ }
+ }
+
+ if(compression == COMP_NONE) {
+ output.write(bpixels, 0, rows * ((tileWidth+7)/8));
+ } else if(compression == COMP_PACKBITS) {
+ int numCompressedBytes =
+ compressPackBits(bpixels, rows,
+ (int)bytesPerRow,
+ compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ } else if(compression == COMP_DEFLATE) {
+ int numCompressedBytes =
+ deflate(deflater, bpixels, compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ }
+
+ break;
+
+ case 4:
+
+ index = 0;
+
+ // For each of the rows in a strip
+ for (int i=0; i<rows; i++) {
+
+ // Write the number of pixels that will fit into an
+ // even number of nibbles.
+ for (int j=0; j < tileWidth/2; j++) {
+ pixel = (pixels[index++] << 4) | pixels[index++];
+ bpixels[k++] = (byte)pixel;
+ }
+
+ // Last pixel for odd-length lines
+ if ((tileWidth & 1) == 1) {
+ pixel = pixels[index++] << 4;
+ bpixels[k++] = (byte)pixel;
+ }
+ }
+
+ if(compression == COMP_NONE) {
+ output.write(bpixels, 0, rows * ((tileWidth+1)/2));
+ } else if(compression == COMP_PACKBITS) {
+ int numCompressedBytes =
+ compressPackBits(bpixels, rows,
+ (int)bytesPerRow,
+ compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ } else if(compression == COMP_DEFLATE) {
+ int numCompressedBytes =
+ deflate(deflater, bpixels, compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ }
+ break;
+
+ case 8:
+
+ if(compression != COMP_JPEG_TTN2) {
+ if(useDataBuffer) {
+ byte[] btmp =
+ ((DataBufferByte)src.getDataBuffer()).getData();
+ ComponentSampleModel csm =
+ (ComponentSampleModel)src.getSampleModel();
+ int inOffset =
+ csm.getOffset(col -
+ src.getSampleModelTranslateX(),
+ row -
+ src.getSampleModelTranslateY());
+ int lineStride = csm.getScanlineStride();
+ if(lineStride == (int)bytesPerRow) {
+ System.arraycopy(btmp,
+ inOffset,
+ bpixels, 0,
+ (int)bytesPerRow*rows);
+ } else {
+ int outOffset = 0;
+ for(int j = 0; j < rows; j++) {
+ System.arraycopy(btmp, inOffset,
+ bpixels, outOffset,
+ (int)bytesPerRow);
+ inOffset += lineStride;
+ outOffset += (int)bytesPerRow;
+ }
+ }
+ } else {
+ for (int i = 0; i < size; i++) {
+ bpixels[i] = (byte)pixels[i];
+ }
+ }
+ }
+
+ if(compression == COMP_NONE) {
+ output.write(bpixels, 0, size);
+ } else if(compression == COMP_PACKBITS) {
+ int numCompressedBytes =
+ compressPackBits(bpixels, rows,
+ (int)bytesPerRow,
+ compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ } else if(compression == COMP_JPEG_TTN2) {
+ long startPos = getOffset(output);
+
+ // Recreate encoder and parameters if the encoder
+ // is null (first data segment) or if its size
+ // doesn't match the current data segment.
+ if(jpegEncoder == null ||
+ jpegEncodeParam.getWidth() != src.getWidth() ||
+ jpegEncodeParam.getHeight() != src.getHeight()) {
+
+ jpegEncodeParam =
+ com.sun.image.codec.jpeg.JPEGCodec.
+ getDefaultJPEGEncodeParam(src, jpegColorID);
+
+ modifyEncodeParam(jep, jpegEncodeParam,
+ numBands);
+
+ jpegEncoder =
+ com.sun.image.codec.jpeg.JPEGCodec.
+ createJPEGEncoder(output, jpegEncodeParam);
+ }
+
+ if(jpegRGBToYCbCr) {
+ WritableRaster wRas = null;
+ if(src instanceof WritableRaster) {
+ wRas = (WritableRaster)src;
+ } else {
+ wRas = src.createCompatibleWritableRaster();
+ wRas.setRect(src);
+ }
+
+ if (wRas.getMinX() != 0 || wRas.getMinY() != 0) {
+ wRas =
+ wRas.createWritableTranslatedChild(0, 0);
+ }
+ BufferedImage bi =
+ new BufferedImage(colorModel, wRas,
+ false, null);
+ jpegEncoder.encode(bi);
+ } else {
+ jpegEncoder.encode(src.createTranslatedChild(0,
+ 0));
+ }
+
+ long endPos = getOffset(output);
+ tileByteCounts[tileNum++] = (int)(endPos - startPos);
+ } else if(compression == COMP_DEFLATE) {
+ int numCompressedBytes =
+ deflate(deflater, bpixels, compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ }
+ break;
+
+ case 16:
+
+ int ls = 0;
+ for (int i = 0; i < size; i++) {
+ int value = pixels[i];
+ bpixels[ls++] = (byte)((value & 0xff00) >> 8);
+ bpixels[ls++] = (byte) (value & 0x00ff);
+ }
+
+ if(compression == COMP_NONE) {
+ output.write(bpixels, 0, size*2);
+ } else if(compression == COMP_PACKBITS) {
+ int numCompressedBytes =
+ compressPackBits(bpixels, rows,
+ (int)bytesPerRow,
+ compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ } else if(compression == COMP_DEFLATE) {
+ int numCompressedBytes =
+ deflate(deflater, bpixels, compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ }
+ break;
+
+ case 32:
+ if(dataType == DataBuffer.TYPE_INT) {
+ int li = 0;
+ for (int i = 0; i < size; i++) {
+ int value = pixels[i];
+ bpixels[li++] = (byte)((value & 0xff000000) >>> 24);
+ bpixels[li++] = (byte)((value & 0x00ff0000) >>> 16);
+ bpixels[li++] = (byte)((value & 0x0000ff00) >>> 8);
+ bpixels[li++] = (byte)( value & 0x000000ff);
+ }
+ } else { // DataBuffer.TYPE_FLOAT
+ int lf = 0;
+ for (int i = 0; i < size; i++) {
+ int value = Float.floatToIntBits(fpixels[i]);
+ bpixels[lf++] = (byte)((value & 0xff000000) >>> 24);
+ bpixels[lf++] = (byte)((value & 0x00ff0000) >>> 16);
+ bpixels[lf++] = (byte)((value & 0x0000ff00) >>> 8);
+ bpixels[lf++] = (byte)( value & 0x000000ff);
+ }
+ }
+ if(compression == COMP_NONE) {
+ output.write(bpixels, 0, size*4);
+ } else if(compression == COMP_PACKBITS) {
+ int numCompressedBytes =
+ compressPackBits(bpixels, rows,
+ (int)bytesPerRow,
+ compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ } else if(compression == COMP_DEFLATE) {
+ int numCompressedBytes =
+ deflate(deflater, bpixels, compressBuf);
+ tileByteCounts[tileNum++] = numCompressedBytes;
+ output.write(compressBuf, 0, numCompressedBytes);
+ }
+ break;
+
+ }
+ }
+ }
+
+ if(compression == COMP_NONE) {
+ // Write an extra byte for IFD word alignment if needed.
+ if(skipByte) {
+ output.write((byte)0);
+ }
+ } else {
+ // Recompute the tile offsets the size of the compressed tiles.
+ int totalBytes = 0;
+ for (int i=1; i<numTiles; i++) {
+ int numBytes = (int)tileByteCounts[i-1];
+ totalBytes += numBytes;
+ tileOffsets[i] = tileOffsets[i-1] + numBytes;
+ }
+ totalBytes += (int)tileByteCounts[numTiles-1];
+
+ nextIFDOffset = isLast ?
+ 0 : ifdOffset + dirSize + totalBytes;
+ if ((nextIFDOffset & 0x01) != 0) { // make it even
+ nextIFDOffset++;
+ skipByte = true;
+ }
+
+ if(outCache == null) {
+ // Original OutputStream must be a SeekableOutputStream.
+
+ // Write an extra byte for IFD word alignment if needed.
+ if(skipByte) {
+ output.write((byte)0);
+ }
+
+ SeekableOutputStream sos = (SeekableOutputStream)output;
+
+ // Save current position.
+ long savePos = sos.getFilePointer();
+
+ // Seek backward to the IFD offset and write IFD.
+ sos.seek(ifdOffset);
+ writeDirectory(ifdOffset, fields, nextIFDOffset);
+
+ // Seek forward to position after data.
+ sos.seek(savePos);
+ } else if(tempFile != null) {
+
+ // Using a file cache for the image data.
+
+ // Open a FileInputStream from which to copy the data.
+ FileInputStream fileStream = new FileInputStream(tempFile);
+
+ // Close the original SeekableOutputStream.
+ output.close();
+
+ // Reset variable to the original OutputStream.
+ output = outCache;
+
+ // Write the IFD.
+ writeDirectory(ifdOffset, fields, nextIFDOffset);
+
+ // Write the image data.
+ byte[] copyBuffer = new byte[8192];
+ int bytesCopied = 0;
+ while(bytesCopied < totalBytes) {
+ int bytesRead = fileStream.read(copyBuffer);
+ if(bytesRead == -1) {
+ break;
+ }
+ output.write(copyBuffer, 0, bytesRead);
+ bytesCopied += bytesRead;
+ }
+
+ // Delete the temporary file.
+ fileStream.close();
+ tempFile.delete();
+
+ // Write an extra byte for IFD word alignment if needed.
+ if(skipByte) {
+ output.write((byte)0);
+ }
+ } else if(output instanceof ByteArrayOutputStream) {
+
+ // Using a memory cache for the image data.
+
+ ByteArrayOutputStream memoryStream =
+ (ByteArrayOutputStream)output;
+
+ // Reset variable to the original OutputStream.
+ output = outCache;
+
+ // Write the IFD.
+ writeDirectory(ifdOffset, fields, nextIFDOffset);
+
+ // Write the image data.
+ memoryStream.writeTo(output);
+
+ // Write an extra byte for IFD word alignment if needed.
+ if(skipByte) {
+ output.write((byte)0);
+ }
+ } else {
+ // This should never happen.
+ throw new IllegalStateException();
+ }
+ }
+
+
+ return nextIFDOffset;
+ }
+
+ /**
+ * Calculates the size of the IFD.
+ */
+ private int getDirectorySize(SortedSet fields) {
+ // Get the number of entries.
+ int numEntries = fields.size();
+
+ // Initialize the size excluding that of any values > 4 bytes.
+ int dirSize = 2 + numEntries*12 + 4;
+
+ // Loop over fields adding the size of all values > 4 bytes.
+ Iterator iter = fields.iterator();
+ while(iter.hasNext()) {
+ // Get the field.
+ TIFFField field = (TIFFField)iter.next();
+
+ // Determine the size of the field value.
+ int valueSize = field.getCount()*sizeOfType[field.getType()];
+
+ // Add any excess size.
+ if(valueSize > 4) {
+ dirSize += valueSize;
+ }
+ }
+
+ return dirSize;
+ }
+
+ private void writeFileHeader() throws IOException {
+ // 8 byte image file header
+
+ // Byte order used within the file - Big Endian
+ output.write('M');
+ output.write('M');
+
+ // Magic value
+ output.write(0);
+ output.write(42);
+
+ // Offset in bytes of the first IFD.
+ writeLong(8);
+ }
+
+ private void writeDirectory(int thisIFDOffset, SortedSet fields,
+ int nextIFDOffset)
+ throws IOException {
+
+ // 2 byte count of number of directory entries (fields)
+ int numEntries = fields.size();
+
+ long offsetBeyondIFD = thisIFDOffset + 12 * numEntries + 4 + 2;
+ List tooBig = new ArrayList();
+
+ // Write number of fields in the IFD
+ writeUnsignedShort(numEntries);
+
+ Iterator iter = fields.iterator();
+ while(iter.hasNext()) {
+
+ // 12 byte field entry TIFFField
+ TIFFField field = (TIFFField)iter.next();
+
+ // byte 0-1 Tag that identifies a field
+ int tag = field.getTag();
+ writeUnsignedShort(tag);
+
+ // byte 2-3 The field type
+ int type = field.getType();
+ writeUnsignedShort(type);
+
+ // bytes 4-7 the number of values of the indicated type except
+ // ASCII-valued fields which require the total number of bytes.
+ int count = field.getCount();
+ int valueSize = getValueSize(field);
+ writeLong(type == TIFFField.TIFF_ASCII ? valueSize : count);
+
+ // bytes 8 - 11 the value or value offset
+ if (valueSize > 4) {
+
+ // We need an offset as data won't fit into 4 bytes
+ writeLong(offsetBeyondIFD);
+ offsetBeyondIFD += valueSize;
+ tooBig.add(field);
+
+ } else {
+ writeValuesAsFourBytes(field);
+ }
+
+ }
+
+ // Address of next IFD
+ writeLong(nextIFDOffset);
+
+ // Write the tag values that did not fit into 4 bytes
+ for (int i = 0; i < tooBig.size(); i++) {
+ writeValues((TIFFField)tooBig.get(i));
+ }
+ }
+
+ /**
+ * Determine the number of bytes in the value portion of the field.
+ */
+ private static int getValueSize(TIFFField field) {
+ int type = field.getType();
+ int count = field.getCount();
+ int valueSize = 0;
+ if(type == TIFFField.TIFF_ASCII) {
+ for(int i = 0; i < count; i++) {
+ byte[] stringBytes = field.getAsString(i).getBytes(); // note: default encoding @work here!
+ valueSize += stringBytes.length;
+ if( stringBytes[stringBytes.length-1] != 0 ) {
+ valueSize++;
+ }
+ }
+ } else {
+ valueSize = count * sizeOfType[type];
+ }
+ return valueSize;
+ }
+
+ private static final int[] sizeOfType = {
+ 0, // 0 = n/a
+ 1, // 1 = byte
+ 1, // 2 = ascii
+ 2, // 3 = short
+ 4, // 4 = long
+ 8, // 5 = rational
+ 1, // 6 = sbyte
+ 1, // 7 = undefined
+ 2, // 8 = sshort
+ 4, // 9 = slong
+ 8, // 10 = srational
+ 4, // 11 = float
+ 8 // 12 = double
+ };
+
+ private void writeValuesAsFourBytes(TIFFField field) throws IOException {
+
+ int dataType = field.getType();
+ int count = field.getCount();
+
+ switch (dataType) {
+
+ // unsigned 8 bits
+ case TIFFField.TIFF_BYTE:
+ byte[] bytes = field.getAsBytes();
+ if (count > 4) count =4;
+ for (int i=0; i<count; i++)
+ output.write(bytes[i]);
+
+ for (int i = 0; i < (4 - count); i++)
+ output.write(0);
+ break;
+
+ // unsigned 16 bits
+ case TIFFField.TIFF_SHORT:
+ char[] chars = field.getAsChars();
+ if (count > 2) count=2;
+ for (int i=0; i<count; i++)
+ writeUnsignedShort(chars[i]);
+ for (int i = 0; i < (2 - count); i++)
+ writeUnsignedShort(0);
+
+ break;
+
+ // unsigned 32 bits
+ case TIFFField.TIFF_LONG:
+ long[] longs = field.getAsLongs();
+
+ for (int i=0; i<count; i++) {
+ writeLong(longs[i]);
+ }
+ break;
+ }
+
+ }
+
+ private void writeValues(TIFFField field) throws IOException {
+
+ int dataType = field.getType();
+ int count = field.getCount();
+
+ switch (dataType) {
+
+ // unsigned 8 bits
+ case TIFFField.TIFF_BYTE:
+ case TIFFField.TIFF_SBYTE:
+ case TIFFField.TIFF_UNDEFINED:
+ byte[] bytes = field.getAsBytes();
+ for (int i=0; i<count; i++) {
+ output.write(bytes[i]);
+ }
+ break;
+
+ // unsigned 16 bits
+ case TIFFField.TIFF_SHORT:
+ char[] chars = field.getAsChars();
+ for (int i=0; i<count; i++) {
+ writeUnsignedShort(chars[i]);
+ }
+ break;
+ case TIFFField.TIFF_SSHORT:
+ short[] shorts = field.getAsShorts();
+ for (int i=0; i<count; i++) {
+ writeUnsignedShort(shorts[i]);
+ }
+ break;
+
+ // unsigned 32 bits
+ case TIFFField.TIFF_LONG:
+ case TIFFField.TIFF_SLONG:
+ long[] longs = field.getAsLongs();
+ for (int i=0; i<count; i++) {
+ writeLong(longs[i]);
+ }
+ break;
+
+ case TIFFField.TIFF_FLOAT:
+ float[] floats = field.getAsFloats();
+ for (int i=0; i<count; i++) {
+ int intBits = Float.floatToIntBits(floats[i]);
+ writeLong(intBits);
+ }
+ break;
+
+ case TIFFField.TIFF_DOUBLE:
+ double[] doubles = field.getAsDoubles();
+ for (int i=0; i<count; i++) {
+ long longBits = Double.doubleToLongBits(doubles[i]);
+ writeLong(longBits >>> 32); // write upper 32 bits
+ writeLong(longBits & 0xffffffffL); // write lower 32 bits
+ }
+ break;
+
+ case TIFFField.TIFF_RATIONAL:
+ case TIFFField.TIFF_SRATIONAL:
+ long[][] rationals = field.getAsRationals();
+ for (int i=0; i<count; i++) {
+ writeLong(rationals[i][0]);
+ writeLong(rationals[i][1]);
+ }
+ break;
+
+ case TIFFField.TIFF_ASCII:
+ for (int i=0; i<count; i++) {
+ byte[] stringBytes = field.getAsString(i).getBytes();
+ output.write(stringBytes);
+ if(stringBytes[stringBytes.length-1] != (byte)0) {
+ output.write((byte)0);
+ }
+ }
+ break;
+
+ default:
+ throw new Error("TIFFImageEncoder10");
+
+ }
+
+ }
+
+ // Here s is never expected to have value greater than what can be
+ // stored in 2 bytes.
+ private void writeUnsignedShort(int s) throws IOException {
+ output.write((s & 0xff00) >>> 8);
+ output.write( s & 0x00ff);
+ }
+
+ /**
+ * despite its name, this method writes only 4 bytes to output.
+ * @param l 32bits of this are written as 4 bytes
+ * @throws IOException
+ */
+ private void writeLong(long l) throws IOException {
+ output.write( (int)((l & 0xff000000) >>> 24));
+ output.write( (int)((l & 0x00ff0000) >>> 16));
+ output.write( (int)((l & 0x0000ff00) >>> 8));
+ output.write( (int) (l & 0x000000ff) );
+ }
+
+ /**
+ * Returns the current offset in the supplied OutputStream.
+ * This method should only be used if compressing data.
+ */
+ private long getOffset(OutputStream out) throws IOException {
+ if(out instanceof ByteArrayOutputStream) {
+ return ((ByteArrayOutputStream)out).size();
+ } else if(out instanceof SeekableOutputStream) {
+ return ((SeekableOutputStream)out).getFilePointer();
+ } else {
+ // Shouldn't happen.
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Performs PackBits compression on a tile of data.
+ */
+ private static int compressPackBits(byte[] data, int numRows,
+ int bytesPerRow, byte[] compData) {
+ int inOffset = 0;
+ int outOffset = 0;
+
+ for(int i = 0; i < numRows; i++) {
+ outOffset = packBits(data, inOffset, bytesPerRow,
+ compData, outOffset);
+ inOffset += bytesPerRow;
+ }
+
+ return outOffset;
+ }
+
+ /**
+ * Performs PackBits compression for a single buffer of data.
+ * This should be called for each row of each tile. The returned
+ * value is the offset into the output buffer after compression.
+ */
+ private static int packBits(byte[] input, int inOffset, int inCount,
+ byte[] output, int outOffset) {
+ int inMax = inOffset + inCount - 1;
+ int inMaxMinus1 = inMax - 1;
+
+ while(inOffset <= inMax) {
+ int run = 1;
+ byte replicate = input[inOffset];
+ while(run < 127 && inOffset < inMax &&
+ input[inOffset] == input[inOffset+1]) {
+ run++;
+ inOffset++;
+ }
+ if(run > 1) {
+ inOffset++;
+ output[outOffset++] = (byte)(-(run - 1));
+ output[outOffset++] = replicate;
+ }
+
+ run = 0;
+ int saveOffset = outOffset;
+ while(run < 128 &&
+ ((inOffset < inMax &&
+ input[inOffset] != input[inOffset+1]) ||
+ (inOffset < inMaxMinus1 &&
+ input[inOffset] != input[inOffset+2]))) {
+ run++;
+ output[++outOffset] = input[inOffset++];
+ }
+ if(run > 0) {
+ output[saveOffset] = (byte)(run - 1);
+ outOffset++;
+ }
+
+ if(inOffset == inMax) {
+ if(run > 0 && run < 128) {
+ output[saveOffset]++;
+ output[outOffset++] = input[inOffset++];
+ } else {
+ output[outOffset++] = (byte)0;
+ output[outOffset++] = input[inOffset++];
+ }
+ }
+ }
+
+ return outOffset;
+ }
+
+ private static int deflate(Deflater deflater,
+ byte[] inflated, byte[] deflated) {
+ deflater.setInput(inflated);
+ deflater.finish();
+ int numCompressedBytes = deflater.deflate(deflated);
+ deflater.reset();
+ return numCompressedBytes;
+ }
+
+ private static void modifyEncodeParam(JPEGEncodeParam src,
+ JPEGEncodeParam dst,
+ int nbands) {
+ dst.setDensityUnit (src.getDensityUnit());
+ dst.setXDensity (src.getXDensity());
+ dst.setYDensity (src.getYDensity());
+ dst.setRestartInterval(src.getRestartInterval());
+ for (int i=0; i<4; i++) {
+ JPEGQTable tbl = src.getQTable(i);
+ if (tbl != null)
+ dst.setQTable(i, tbl);
+ }
+ }
+}
+
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFLZWDecoder.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFLZWDecoder.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFLZWDecoder.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFLZWDecoder.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,243 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+package org.apache.flex.forks.batik.ext.awt.image.codec.tiff;
+
+/**
+ * A class for performing LZW decoding.
+ *
+ * @version $Id: TIFFLZWDecoder.java 498740 2007-01-22 18:35:57Z dvholten $
+ */
+public class TIFFLZWDecoder {
+
+ byte[][] stringTable;
+ byte[] data = null;
+ byte[] uncompData;
+ int tableIndex, bitsToGet = 9;
+ int bytePointer, bitPointer;
+ int dstIndex;
+ int w, h;
+ int predictor, samplesPerPixel;
+ int nextData = 0;
+ int nextBits = 0;
+
+ int[] andTable = {
+ 511,
+ 1023,
+ 2047,
+ 4095
+ };
+
+ public TIFFLZWDecoder(int w, int predictor, int samplesPerPixel) {
+ this.w = w;
+ this.predictor = predictor;
+ this.samplesPerPixel = samplesPerPixel;
+ }
+
+ /**
+ * Method to decode LZW compressed data.
+ *
+ * @param data The compressed data.
+ * @param uncompData Array to return the uncompressed data in.
+ * @param h The number of rows the compressed data contains.
+ */
+ public byte[] decode(byte[] data, byte[] uncompData, int h) {
+
+ if(data[0] == (byte)0x00 && data[1] == (byte)0x01) {
+ throw new UnsupportedOperationException("TIFFLZWDecoder0");
+ }
+
+ initializeStringTable();
+
+ this.data = data;
+ this.h = h;
+ this.uncompData = uncompData;
+
+ // Initialize pointers
+ bytePointer = 0;
+ bitPointer = 0;
+ dstIndex = 0;
+
+
+ nextData = 0;
+ nextBits = 0;
+
+ int code, oldCode = 0;
+ byte[] string;
+
+ while ( ((code = getNextCode()) != 257) &&
+ dstIndex != uncompData.length) {
+
+ if (code == 256) {
+
+ initializeStringTable();
+ code = getNextCode();
+
+ if (code == 257) {
+ break;
+ }
+
+ writeString(stringTable[code]);
+ oldCode = code;
+
+ } else {
+
+ if (code < tableIndex) {
+
+ string = stringTable[code];
+
+ writeString(string);
+ addStringToTable(stringTable[oldCode], string[0]);
+ oldCode = code;
+
+ } else {
+
+ string = stringTable[oldCode];
+ string = composeString(string, string[0]);
+ writeString(string);
+ addStringToTable(string);
+ oldCode = code;
+ }
+
+ }
+
+ }
+
+ // Horizontal Differencing Predictor
+ if (predictor == 2) {
+
+ int count;
+ for (int j = 0; j < h; j++) {
+
+ count = samplesPerPixel * (j * w + 1);
+
+ for (int i = samplesPerPixel; i < w * samplesPerPixel; i++) {
+
+ uncompData[count] += uncompData[count - samplesPerPixel];
+ count++;
+ }
+ }
+ }
+
+ return uncompData;
+ }
+
+
+ /**
+ * Initialize the string table.
+ */
+ public void initializeStringTable() {
+
+ stringTable = new byte[4096][];
+
+ for (int i=0; i<256; i++) {
+ stringTable[i] = new byte[1];
+ stringTable[i][0] = (byte)i;
+ }
+
+ tableIndex = 258;
+ bitsToGet = 9;
+ }
+
+ /**
+ * Write out the string just uncompressed.
+ */
+ public void writeString(byte[] string) {
+
+ for (int i=0; i<string.length; i++) {
+ uncompData[dstIndex++] = string[i];
+ }
+ }
+
+ /**
+ * Add a new string to the string table.
+ */
+ public void addStringToTable(byte[] oldString, byte newString) {
+ int length = oldString.length;
+ byte[] string = new byte[length + 1];
+ System.arraycopy(oldString, 0, string, 0, length);
+ string[length] = newString;
+
+ // Add this new String to the table
+ stringTable[tableIndex++] = string;
+
+ if (tableIndex == 511) {
+ bitsToGet = 10;
+ } else if (tableIndex == 1023) {
+ bitsToGet = 11;
+ } else if (tableIndex == 2047) {
+ bitsToGet = 12;
+ }
+ }
+
+ /**
+ * Add a new string to the string table.
+ */
+ public void addStringToTable(byte[] string) {
+
+ // Add this new String to the table
+ stringTable[tableIndex++] = string;
+
+ if (tableIndex == 511) {
+ bitsToGet = 10;
+ } else if (tableIndex == 1023) {
+ bitsToGet = 11;
+ } else if (tableIndex == 2047) {
+ bitsToGet = 12;
+ }
+ }
+
+ /**
+ * Append <code>newString</code> to the end of <code>oldString</code>.
+ */
+ public byte[] composeString(byte[] oldString, byte newString) {
+ int length = oldString.length;
+ byte[] string = new byte[length + 1];
+ System.arraycopy(oldString, 0, string, 0, length);
+ string[length] = newString;
+
+ return string;
+ }
+
+ // Returns the next 9, 10, 11 or 12 bits
+ public int getNextCode() {
+ // Attempt to get the next code. The exception is caught to make
+ // this robust to cases wherein the EndOfInformation code has been
+ // omitted from a strip. Examples of such cases have been observed
+ // in practice.
+ try {
+ nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
+ nextBits += 8;
+
+ if (nextBits < bitsToGet) {
+ nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
+ nextBits += 8;
+ }
+
+ int code =
+ (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet-9];
+ nextBits -= bitsToGet;
+
+ return code;
+ } catch(ArrayIndexOutOfBoundsException e) {
+ // Strip not terminated as expected: return EndOfInformation code.
+ return 257;
+ }
+ }
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFLZWDecoder.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFRegistryEntry.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFRegistryEntry.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFRegistryEntry.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFRegistryEntry.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,110 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.codec.tiff;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.flex.forks.batik.ext.awt.image.codec.util.SeekableStream;
+import org.apache.flex.forks.batik.ext.awt.image.renderable.DeferRable;
+import org.apache.flex.forks.batik.ext.awt.image.renderable.Filter;
+import org.apache.flex.forks.batik.ext.awt.image.renderable.RedRable;
+import org.apache.flex.forks.batik.ext.awt.image.rendered.Any2sRGBRed;
+import org.apache.flex.forks.batik.ext.awt.image.rendered.CachableRed;
+import org.apache.flex.forks.batik.ext.awt.image.spi.ImageTagRegistry;
+import org.apache.flex.forks.batik.ext.awt.image.spi.MagicNumberRegistryEntry;
+import org.apache.flex.forks.batik.util.ParsedURL;
+
+/**
+ *
+ * @version $Id: TIFFRegistryEntry.java 501094 2007-01-29 16:35:37Z deweese $
+ */
+public class TIFFRegistryEntry
+ extends MagicNumberRegistryEntry {
+
+ static final byte [] sig1 = {(byte)0x49, (byte)0x49, 42, 0};
+ static final byte [] sig2 = {(byte)0x4D, (byte)0x4D, 0, 42};
+
+ static MagicNumberRegistryEntry.MagicNumber [] magicNumbers = {
+ new MagicNumberRegistryEntry.MagicNumber(0, sig1),
+ new MagicNumberRegistryEntry.MagicNumber(0, sig2) };
+
+ static final String [] exts = {"tiff", "tif" };
+ static final String [] mimeTypes = {"image/tiff", "image/tif" };
+
+ public TIFFRegistryEntry() {
+ super("TIFF", exts, mimeTypes, magicNumbers);
+ }
+
+ /**
+ * Decode the Stream into a RenderableImage
+ *
+ * @param inIS The input stream that contains the image.
+ * @param origURL The original URL, if any, for documentation
+ * purposes only. This may be null.
+ * @param needRawData If true the image returned should not have
+ * any default color correction the file may
+ * specify applied.
+ */
+ public Filter handleStream(InputStream inIS,
+ ParsedURL origURL,
+ boolean needRawData) {
+
+ final DeferRable dr = new DeferRable();
+ final InputStream is = inIS;
+ final String errCode;
+ final Object [] errParam;
+ if (origURL != null) {
+ errCode = ERR_URL_FORMAT_UNREADABLE;
+ errParam = new Object[] {"TIFF", origURL};
+ } else {
+ errCode = ERR_STREAM_FORMAT_UNREADABLE;
+ errParam = new Object[] {"TIFF"};
+ }
+
+ Thread t = new Thread() {
+ public void run() {
+ Filter filt;
+ try {
+ TIFFDecodeParam param = new TIFFDecodeParam();
+ SeekableStream ss =
+ SeekableStream.wrapInputStream(is, true);
+ CachableRed cr = new TIFFImage(ss, param, 0);
+ cr = new Any2sRGBRed(cr);
+ filt = new RedRable(cr);
+ } catch (IOException ioe) {
+ filt = ImageTagRegistry.getBrokenLinkImage
+ (TIFFRegistryEntry.this, errCode, errParam);
+ } catch (ThreadDeath td) {
+ filt = ImageTagRegistry.getBrokenLinkImage
+ (TIFFRegistryEntry.this, errCode, errParam);
+ dr.setSource(filt);
+ throw td;
+ } catch (Throwable t) {
+ filt = ImageTagRegistry.getBrokenLinkImage
+ (TIFFRegistryEntry.this, errCode, errParam);
+ }
+
+ dr.setSource(filt);
+ }
+ };
+ t.start();
+ return dr;
+ }
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFRegistryEntry.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFTranscoderInternalCodecWriteAdapter.java
URL: http://svn.apache.org/viewvc/incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFTranscoderInternalCodecWriteAdapter.java?rev=1402274&view=auto
==============================================================================
--- incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFTranscoderInternalCodecWriteAdapter.java (added)
+++ incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFTranscoderInternalCodecWriteAdapter.java Thu Oct 25 19:01:43 2012
@@ -0,0 +1,114 @@
+/*
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.apache.flex.forks.batik.ext.awt.image.codec.tiff;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.flex.forks.batik.ext.awt.image.GraphicsUtil;
+import org.apache.flex.forks.batik.ext.awt.image.rendered.FormatRed;
+import org.apache.flex.forks.batik.transcoder.TranscoderException;
+import org.apache.flex.forks.batik.transcoder.TranscoderOutput;
+import org.apache.flex.forks.batik.transcoder.TranscodingHints;
+import org.apache.flex.forks.batik.transcoder.image.TIFFTranscoder;
+
+/**
+ * This class is a helper to <tt>TIFFTranscoder</tt> that writes TIFF images
+ * through the internal TIFF codec.
+ *
+ * @version $Id: TIFFTranscoderInternalCodecWriteAdapter.java 582434 2007-10-06 02:11:51Z cam $
+ */
+public class TIFFTranscoderInternalCodecWriteAdapter implements
+ TIFFTranscoder.WriteAdapter {
+
+ /**
+ * @throws TranscoderException
+ * @see org.apache.flex.forks.batik.transcoder.image.PNGTranscoder.WriteAdapter#writeImage(org.apache.flex.forks.batik.transcoder.image.PNGTranscoder, java.awt.image.BufferedImage, org.apache.flex.forks.batik.transcoder.TranscoderOutput)
+ */
+ public void writeImage(TIFFTranscoder transcoder, BufferedImage img,
+ TranscoderOutput output) throws TranscoderException {
+ TranscodingHints hints = transcoder.getTranscodingHints();
+
+ TIFFEncodeParam params = new TIFFEncodeParam();
+
+ float PixSzMM = transcoder.getUserAgent().getPixelUnitToMillimeter();
+ // num Pixs in 100 Meters
+ int numPix = (int)(((1000 * 100) / PixSzMM) + 0.5);
+ int denom = 100 * 100; // Centimeters per 100 Meters;
+ long [] rational = {numPix, denom};
+ TIFFField [] fields = {
+ new TIFFField(TIFFImageDecoder.TIFF_RESOLUTION_UNIT,
+ TIFFField.TIFF_SHORT, 1,
+ new char [] { (char)3 }),
+ new TIFFField(TIFFImageDecoder.TIFF_X_RESOLUTION,
+ TIFFField.TIFF_RATIONAL, 1,
+ new long [][] { rational }),
+ new TIFFField(TIFFImageDecoder.TIFF_Y_RESOLUTION,
+ TIFFField.TIFF_RATIONAL, 1,
+ new long [][] { rational })
+ };
+
+ params.setExtraFields(fields);
+
+ if (hints.containsKey(TIFFTranscoder.KEY_COMPRESSION_METHOD)) {
+ String method = (String)hints.get(TIFFTranscoder.KEY_COMPRESSION_METHOD);
+ if ("packbits".equals(method)) {
+ params.setCompression(TIFFEncodeParam.COMPRESSION_PACKBITS);
+ } else if ("deflate".equals(method)) {
+ params.setCompression(TIFFEncodeParam.COMPRESSION_DEFLATE);
+ /* TODO: NPE occurs when used.
+ } else if ("jpeg".equals(method)) {
+ params.setCompression(TIFFEncodeParam.COMPRESSION_JPEG_TTN2);
+ */
+ } else {
+ //nop
+ }
+ }
+
+
+ try {
+ int w = img.getWidth();
+ int h = img.getHeight();
+ SinglePixelPackedSampleModel sppsm;
+ sppsm = (SinglePixelPackedSampleModel)img.getSampleModel();
+ OutputStream ostream = output.getOutputStream();
+ TIFFImageEncoder tiffEncoder =
+ new TIFFImageEncoder(ostream, params);
+ int bands = sppsm.getNumBands();
+ int [] off = new int[bands];
+ for (int i = 0; i < bands; i++)
+ off[i] = i;
+ SampleModel sm = new PixelInterleavedSampleModel
+ (DataBuffer.TYPE_BYTE, w, h, bands, w * bands, off);
+
+ RenderedImage rimg = new FormatRed(GraphicsUtil.wrap(img), sm);
+ tiffEncoder.encode(rimg);
+ ostream.flush();
+ } catch (IOException ex) {
+ throw new TranscoderException(ex);
+ }
+ }
+
+}
Propchange: incubator/flex/sdk/branches/develop/modules/thirdparty/batik/sources/org/apache/flex/forks/batik/ext/awt/image/codec/tiff/TIFFTranscoderInternalCodecWriteAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native