final Object firstKey = params.keySet().iterator().next();
throw new ImageWriteException("Unknown parameter: " + firstKey);
}
final PaletteFactory paletteFactory = new PaletteFactory();
final SimplePalette palette = paletteFactory
.makeExactRgbPaletteSimple(src, 256);
final int bitCount;
final boolean hasTransparency = paletteFactory.hasTransparency(src);
if (palette == null) {
if (hasTransparency) {
bitCount = 32;
} else {
bitCount = 24;
}
} else if (palette.length() <= 2) {
bitCount = 1;
} else if (palette.length() <= 16) {
bitCount = 4;
} else {
bitCount = 8;
}
final BinaryOutputStream bos = new BinaryOutputStream(os, ByteOrder.LITTLE_ENDIAN);
int scanline_size = (bitCount * src.getWidth() + 7) / 8;
if ((scanline_size % 4) != 0) {
scanline_size += 4 - (scanline_size % 4); // pad scanline to 4 byte
// size.
}
int t_scanline_size = (src.getWidth() + 7) / 8;
if ((t_scanline_size % 4) != 0) {
t_scanline_size += 4 - (t_scanline_size % 4); // pad scanline to 4
// byte size.
}
final int imageSize = 40 + 4 * (bitCount <= 8 ? (1 << bitCount) : 0)
+ src.getHeight() * scanline_size + src.getHeight()
* t_scanline_size;
// ICONDIR
bos.write2Bytes(0); // reserved
bos.write2Bytes(1); // 1=ICO, 2=CUR
bos.write2Bytes(1); // count
// ICONDIRENTRY
int iconDirEntryWidth = src.getWidth();
int iconDirEntryHeight = src.getHeight();
if (iconDirEntryWidth > 255 || iconDirEntryHeight > 255) {
iconDirEntryWidth = 0;
iconDirEntryHeight = 0;
}
bos.write(iconDirEntryWidth);
bos.write(iconDirEntryHeight);
bos.write((bitCount >= 8) ? 0 : (1 << bitCount));
bos.write(0); // reserved
bos.write2Bytes(1); // color planes
bos.write2Bytes(bitCount);
bos.write4Bytes(imageSize);
bos.write4Bytes(22); // image offset
// BITMAPINFOHEADER
bos.write4Bytes(40); // size
bos.write4Bytes(src.getWidth());
bos.write4Bytes(2 * src.getHeight());
bos.write2Bytes(1); // planes
bos.write2Bytes(bitCount);
bos.write4Bytes(0); // compression
bos.write4Bytes(0); // image size
bos.write4Bytes(pixelDensity == null ? 0 : (int) Math.round(pixelDensity.horizontalDensityMetres())); // x pixels per meter
bos.write4Bytes(pixelDensity == null ? 0 : (int) Math.round(pixelDensity.horizontalDensityMetres())); // y pixels per meter
bos.write4Bytes(0); // colors used, 0 = (1 << bitCount) (ignored)
bos.write4Bytes(0); // colors important
if (palette != null) {
for (int i = 0; i < (1 << bitCount); i++) {
if (i < palette.length()) {
final int argb = palette.getEntry(i);
bos.write(0xff & argb);
bos.write(0xff & (argb >> 8));
bos.write(0xff & (argb >> 16));
bos.write(0);
} else {
bos.write(0);
bos.write(0);
bos.write(0);
bos.write(0);
}
}
}
int bitCache = 0;
int bitsInCache = 0;
final int rowPadding = scanline_size - (bitCount * src.getWidth() + 7) / 8;
for (int y = src.getHeight() - 1; y >= 0; y--) {
for (int x = 0; x < src.getWidth(); x++) {
final int argb = src.getRGB(x, y);
if (bitCount < 8) {
final int rgb = 0xffffff & argb;
final int index = palette.getPaletteIndex(rgb);
bitCache <<= bitCount;
bitCache |= index;
bitsInCache += bitCount;
if (bitsInCache >= 8) {
bos.write(0xff & bitCache);
bitCache = 0;
bitsInCache = 0;
}
} else if (bitCount == 8) {
final int rgb = 0xffffff & argb;
final int index = palette.getPaletteIndex(rgb);
bos.write(0xff & index);
} else if (bitCount == 24) {
bos.write(0xff & argb);
bos.write(0xff & (argb >> 8));
bos.write(0xff & (argb >> 16));