if (params.containsKey(PARAM_KEY_XMP_XML)) {
xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
params.remove(PARAM_KEY_XMP_XML);
}
PixelDensity pixelDensity = (PixelDensity) params
.remove(PARAM_KEY_PIXEL_DENSITY);
if (pixelDensity == null) {
pixelDensity = PixelDensity.createFromPixelsPerInch(72, 72);
}
final int width = src.getWidth();
final int height = src.getHeight();
int compression = TIFF_COMPRESSION_LZW; // LZW is default
if (params.containsKey(PARAM_KEY_COMPRESSION)) {
final 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 HashMap<String, Object> rawParams = new HashMap<String, Object>(params);
params.remove(PARAM_KEY_T4_OPTIONS);
params.remove(PARAM_KEY_T6_OPTIONS);
if (!params.isEmpty()) {
final Object firstKey = params.keySet().iterator().next();
throw new ImageWriteException("Unknown parameter: " + firstKey);
}
int samplesPerPixel;
int bitsPerSample;
int photometricInterpretation;
if (compression == TIFF_COMPRESSION_CCITT_1D
|| compression == TIFF_COMPRESSION_CCITT_GROUP_3
|| compression == TIFF_COMPRESSION_CCITT_GROUP_4) {
samplesPerPixel = 1;
bitsPerSample = 1;
photometricInterpretation = 0;
} else {
samplesPerPixel = 3;
bitsPerSample = 8;
photometricInterpretation = 2;
}
int rowsPerStrip = 64000 / (width * bitsPerSample * samplesPerPixel); // TODO:
rowsPerStrip = Math.max(1, rowsPerStrip); // must have at least one.
final byte[][] strips = getStrips(src, samplesPerPixel, bitsPerSample, rowsPerStrip);
// 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);
int t4Options = 0;
int t6Options = 0;
if (compression == TIFF_COMPRESSION_CCITT_1D) {
for (int i = 0; i < strips.length; i++) {
strips[i] = T4AndT6Compression.compressModifiedHuffman(
strips[i], width, strips[i].length / ((width + 7) / 8));
}
} else if (compression == TIFF_COMPRESSION_CCITT_GROUP_3) {
final Integer t4Parameter = (Integer) rawParams.get(PARAM_KEY_T4_OPTIONS);
if (t4Parameter != null) {
t4Options = t4Parameter.intValue();
}
t4Options &= 0x7;
final boolean is2D = (t4Options & 1) != 0;
final boolean usesUncompressedMode = (t4Options & 2) != 0;
if (usesUncompressedMode) {
throw new ImageWriteException(
"T.4 compression with the uncompressed mode extension is not yet supported");
}
final boolean hasFillBitsBeforeEOL = (t4Options & 4) != 0;
for (int i = 0; i < strips.length; i++) {
if (is2D) {
strips[i] = T4AndT6Compression.compressT4_2D(strips[i],
width, strips[i].length / ((width + 7) / 8),
hasFillBitsBeforeEOL, rowsPerStrip);
} else {
strips[i] = T4AndT6Compression.compressT4_1D(strips[i],
width, strips[i].length / ((width + 7) / 8),
hasFillBitsBeforeEOL);
}
}
} else if (compression == TIFF_COMPRESSION_CCITT_GROUP_4) {
final Integer t6Parameter = (Integer) rawParams.get(PARAM_KEY_T6_OPTIONS);
if (t6Parameter != null) {
t6Options = t6Parameter.intValue();
}
t6Options &= 0x4;
final boolean usesUncompressedMode = (t6Options & TIFF_FLAG_T6_OPTIONS_UNCOMPRESSED_MODE) != 0;
if (usesUncompressedMode) {
throw new ImageWriteException(
"T.6 compression with the uncompressed mode extension is not yet supported");
}
for (int i = 0; i < strips.length; i++) {
strips[i] = T4AndT6Compression.compressT6(strips[i], width,
strips[i].length / ((width + 7) / 8));
}
} else 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++) {
final byte[] uncompressed = strips[i];
final int LZW_MINIMUM_CODE_SIZE = 8;
final MyLzwCompressor compressor = new MyLzwCompressor(
LZW_MINIMUM_CODE_SIZE, ByteOrder.BIG_ENDIAN, true);
final byte[] compressed = compressor.compress(uncompressed);
strips[i] = compressed;
}
} else if (compression == TIFF_COMPRESSION_UNCOMPRESSED) {
// do nothing.
} else {
throw new ImageWriteException(
"Invalid compression parameter (Only CCITT 1D/Group 3/Group 4, LZW, Packbits and uncompressed supported).");
}
final 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]);
}
final TiffOutputSet outputSet = new TiffOutputSet(byteOrder);
final TiffOutputDirectory directory = outputSet.addRootDirectory();
// WriteField stripOffsetsField;
{
directory.add(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, width);
directory.add(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, height);
directory.add(TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION,
(short) photometricInterpretation);
directory.add(TiffTagConstants.TIFF_TAG_COMPRESSION,
(short) compression);
directory.add(TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL,
(short) samplesPerPixel);
if (samplesPerPixel == 3) {
directory.add(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE,
(short) bitsPerSample, (short) bitsPerSample,
(short) bitsPerSample);
} else if (samplesPerPixel == 1) {
directory.add(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE,
(short) bitsPerSample);
}
// {
// 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);
// }
directory.add(TiffTagConstants.TIFF_TAG_ROWS_PER_STRIP,
rowsPerStrip);
if (pixelDensity.isUnitless()) {
directory.add(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT,
(short) 0);
directory.add(TiffTagConstants.TIFF_TAG_XRESOLUTION,
RationalNumber.valueOf(pixelDensity.getRawHorizontalDensity()));
directory.add(TiffTagConstants.TIFF_TAG_YRESOLUTION,
RationalNumber.valueOf(pixelDensity.getRawVerticalDensity()));
} else if (pixelDensity.isInInches()) {
directory.add(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT,
(short) 2);
directory.add(TiffTagConstants.TIFF_TAG_XRESOLUTION,
RationalNumber.valueOf(pixelDensity.horizontalDensityInches()));
directory.add(TiffTagConstants.TIFF_TAG_YRESOLUTION,
RationalNumber.valueOf(pixelDensity.verticalDensityInches()));
} else {
directory.add(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT,
(short) 1);
directory.add(TiffTagConstants.TIFF_TAG_XRESOLUTION,
RationalNumber.valueOf(pixelDensity.horizontalDensityCentimetres()));
directory.add(TiffTagConstants.TIFF_TAG_YRESOLUTION,
RationalNumber.valueOf(pixelDensity.verticalDensityCentimetres()));
}
if (t4Options != 0) {
directory.add(TiffTagConstants.TIFF_TAG_T4_OPTIONS, t4Options);
}
if (t6Options != 0) {