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:
if (colorModel.hasAlpha()) {
jpegColorID = com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_RGBA;
} else {
jpegColorID = com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_RGB;
}
break;
case TIFF_YCBCR:
if (colorModel.hasAlpha()) {
jpegColorID = com.sun.image.codec.jpeg.JPEGDecodeParam.COLOR_ID_YCbCrA;
} else {
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;
}
}
}