in src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java [602:766]
public void writeImage(final BufferedImage src, final OutputStream os, IcoImagingParameters params) throws ImagingException, IOException {
if (params == null) {
params = new IcoImagingParameters();
}
final PixelDensity pixelDensity = params.getPixelDensity();
final PaletteFactory paletteFactory = new PaletteFactory();
final SimplePalette palette = paletteFactory.makeExactRgbPaletteSimple(src, 256);
final int bitCount;
// If we can't obtain an exact rgb palette, we set the bit count to either 24 or 32
// so there is a relation between having a palette and the bit count.
if (palette == null) {
final boolean hasTransparency = paletteFactory.hasTransparency(src);
if (hasTransparency) {
bitCount = 32;
} else {
bitCount = 24;
}
} else if (palette.length() <= 2) {
bitCount = 1;
} else if (palette.length() <= 16) {
bitCount = 4;
} else {
bitCount = 8;
}
try (AbstractBinaryOutputStream bos = AbstractBinaryOutputStream.littleEndian(os)) {
int scanlineSize = (bitCount * src.getWidth() + 7) / 8;
if (scanlineSize % 4 != 0) {
scanlineSize += 4 - scanlineSize % 4; // pad scanline to 4 byte
// size.
}
int tScanlineSize = (src.getWidth() + 7) / 8;
if (tScanlineSize % 4 != 0) {
tScanlineSize += 4 - tScanlineSize % 4; // pad scanline to 4
// byte size.
}
final int imageSize = 40 + 4 * (bitCount <= 8 ? 1 << bitCount : 0) + src.getHeight() * scanlineSize + src.getHeight() * tScanlineSize;
// 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.write3Bytes(argb);
bos.write(0);
} else {
bos.write4Bytes(0);
}
}
}
int bitCache = 0;
int bitsInCache = 0;
final int rowPadding = scanlineSize - (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);
// Remember there is a relation between having a rgb palette and the bit count, see above comment
if (palette == null) {
if (bitCount == 24) {
bos.write3Bytes(argb);
} else if (bitCount == 32) {
bos.write4Bytes(argb);
}
} else 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);
}
}
if (bitsInCache > 0) {
bitCache <<= 8 - bitsInCache;
bos.write(0xff & bitCache);
bitCache = 0;
bitsInCache = 0;
}
for (int x = 0; x < rowPadding; x++) {
bos.write(0);
}
}
final int tRowPadding = tScanlineSize - (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);
final int alpha = 0xff & argb >> 24;
bitCache <<= 1;
if (alpha == 0) {
bitCache |= 1;
}
bitsInCache++;
if (bitsInCache >= 8) {
bos.write(0xff & bitCache);
bitCache = 0;
bitsInCache = 0;
}
}
if (bitsInCache > 0) {
bitCache <<= 8 - bitsInCache;
bos.write(0xff & bitCache);
bitCache = 0;
bitsInCache = 0;
}
for (int x = 0; x < tRowPadding; x++) {
bos.write(0);
}
}
}
}