File tempFile = null;
int nextIFDOffset = 0;
boolean skipByte = false;
Deflater deflater = null;
int deflateLevel = Deflater.DEFAULT_COMPRESSION;
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 % 2 != 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);
// XXX Be sure that this file is deleted no matter how
// this method is exited!
} catch(Exception e) {
tempFile = null;
// Allocate memory for the entire image data (!).
output = new ByteArrayOutputStream((int)totalBytesOfData);
}
}
int bufSize = 0;
switch(compression) {
case COMP_GROUP3_1D:
// This initial buffer size is based on an alternating 1-0
// pattern generating the most bits when converted to code
// words: 9 bits out for each pair of bits in. So the number
// of bit pairs is determined, multiplied by 9, converted to
// bytes, and a ceil() is taken to account for fill bits at the
// end of each line. The "2" addend accounts for the case
// of the pattern beginning with black. The buffer is intended
// to hold only a single row.
bufSize = (int)Math.ceil((((tileWidth + 1)/2)*9 + 2)/8.0);
break;
case COMP_GROUP3_2D:
case COMP_GROUP4:
// Calculate the maximum row as the G3-1D size plus the EOL,
// multiply this by the number of rows in the tile, and add
// 6 EOLs for the RTC (return to control).
bufSize = (int)Math.ceil((((tileWidth + 1)/2)*9 + 2)/8.0);
bufSize = tileHeight*(bufSize + 2) + 12;
break;
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) {