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,
(Object)(new long[] {(long)width})));
// Image Length
fields.add(new TIFFField(TIFFImageDecoder.TIFF_IMAGE_LENGTH,
TIFFField.TIFF_LONG, 1,
new long[] {(long)height}));
fields.add(new TIFFField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE,
TIFFField.TIFF_SHORT, numBands,
intsToChars(sampleSize)));
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,
(long[])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[] {(long)tileHeight}));
fields.add(new TIFFField(TIFFImageDecoder.TIFF_STRIP_BYTE_COUNTS,
TIFFField.TIFF_LONG, numTiles,
(long[])tileByteCounts));
}
if (colormap != null) {
fields.add(new TIFFField(TIFFImageDecoder.TIFF_COLORMAP,
TIFFField.TIFF_SHORT, sizeOfColormap,
intsToChars(colormap)));
}
if(isTiled) {
fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_WIDTH,
TIFFField.TIFF_LONG, 1,
new long[] {(long)tileWidth}));
fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_LENGTH,
TIFFField.TIFF_LONG, 1,
new long[] {(long)tileHeight}));
fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_OFFSETS,
TIFFField.TIFF_LONG, numTiles,
(long[])tileOffsets));
fields.add(new TIFFField(TIFFImageDecoder.TIFF_TILE_BYTE_COUNTS,
TIFFField.TIFF_LONG, numTiles,
(long[])tileByteCounts));
}
if(numExtraSamples > 0) {
int[] extraSamples = new int[numExtraSamples];
for(int i = 0; i < numExtraSamples; i++) {
extraSamples[i] = extraSampleType;
}
fields.add(new TIFFField(TIFFImageDecoder.TIFF_EXTRA_SAMPLES,
TIFFField.TIFF_SHORT, numExtraSamples,
intsToChars(extraSamples)));
}
// Data Sample Format Extension fields.
if(dataType != DataBuffer.TYPE_BYTE) {
// SampleFormat
int[] sampleFormat = new int[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,
intsToChars(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.
}
// Bilevel compression variables.
boolean inverseFill = encodeParam.getReverseFillOrder();
boolean T4encode2D = encodeParam.getT4Encode2D();
boolean T4PadEOLs = encodeParam.getT4PadEOLs();
TIFFFaxEncoder faxEncoder = null;
// Add bilevel compression fields.
if((imageType == TIFF_BILEVEL_BLACK_IS_ZERO ||
imageType == TIFF_BILEVEL_WHITE_IS_ZERO) &&
(compression == COMP_GROUP3_1D ||
compression == COMP_GROUP3_2D ||
compression == COMP_GROUP4)) {
// Create the encoder.
faxEncoder = new TIFFFaxEncoder(inverseFill);
// FillOrder field.
fields.add(new TIFFField(TIFFImageDecoder.TIFF_FILL_ORDER,
TIFFField.TIFF_SHORT, 1,
new char[] {inverseFill ?
(char)2 : (char)1}));
if(compression == COMP_GROUP3_2D) {
// T4Options field.
long T4Options = 0x00000000;
if(T4encode2D) {
T4Options |= 0x00000001;
}
if(T4PadEOLs) {
T4Options |= 0x00000004;
}
fields.add(new TIFFField(TIFFImageDecoder.TIFF_T4_OPTIONS,
TIFFField.TIFF_LONG, 1,
new long[] {T4Options}));
} else if(compression == COMP_GROUP4) {
// T6Options field.
fields.add(new TIFFField(TIFFImageDecoder.TIFF_T6_OPTIONS,
TIFFField.TIFF_LONG, 1,
new long[] {(long)0x00000000}));
}
}
// 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(im.getMinTileX(), im.getMinTileY());
jpegEncodeParam =
com.sun.image.codec.jpeg.JPEGCodec.getDefaultJPEGEncodeParam(
tile00, jpegColorID);
// Modify per values passed in.
JPEGImageEncoder.modifyEncodeParam(jep, jpegEncodeParam, numBands);
// JPEGTables field.
if(jep.getWriteImageOnly()) {
// 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.
int subsampleH = 1;
int subsampleV = 1;
// If JPEG, update values.
if(compression == COMP_JPEG_TTN2) {
// Determine maximum subsampling.
subsampleH = jep.getHorizontalSubsampling(0);
subsampleV = jep.getVerticalSubsampling(0);
for(int i = 1; i < numBands; i++) {
int subH = jep.getHorizontalSubsampling(i);
if(subH > subsampleH) {
subsampleH = subH;
}
int subV = jep.getVerticalSubsampling(i);
if(subV > subsampleV) {
subsampleV = subV;
}
}
}