/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.ui.image;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.imageio.stream.FileCacheImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import com.github.jaiimageio.impl.common.PaletteBuilder;
public class ICOGenerator extends AbstractDIBGenerator {
private static final byte[] ICO_MAGIC = { 0, 0 , 1, 0 };
private static final int BYTE_MASK = 0xFF;
private static final int ICONDIR_SIZE = 6;
private static final int ICONDIRENTRY_SIZE = 16;
public void write(OutputStream os) throws IOException {
List<RenderedImage> icons = new ArrayList<>();
for (ICOType iconType : ICOType.values()) {
RenderedImage image = images.get(iconType.getSize());
if (image == null)
throw new IllegalArgumentException("incomplete image dimesions");
icons.add(iconType.isIndexed() ? PaletteBuilder.createIndexedImage(image) : image);
}
try (ImageOutputStream ios = new FileCacheImageOutputStream(os, null)) {
ios.setByteOrder(ByteOrder.LITTLE_ENDIAN);
ios.write(ICO_MAGIC);
ios.writeShort(icons.size());
int offset = calculateIconHeaderSize(icons.size());
for (RenderedImage image : icons)
offset = writeIconDirEntry(ios, image, offset);
for (RenderedImage image : icons)
writeIconImage(ios, image, true);
}
}
protected int calculateIconHeaderSize(int iconNumber) {
return ICONDIR_SIZE + ICONDIRENTRY_SIZE * iconNumber;
}
protected int writeIconDirEntry(ImageOutputStream ios, RenderedImage image, int offset) throws IOException {
ios.writeByte(image.getWidth() & BYTE_MASK);
ios.writeByte(image.getHeight() & BYTE_MASK);
ios.writeShort(0);
ios.writeShort(1);
ios.writeShort(image.getColorModel().getPixelSize());
int size = calculateIconImageSize(image);
ios.writeInt(size);
ios.writeInt(offset);
return offset + size;
}
protected int calculateIconImageSize(RenderedImage image) {
int pixelBytes = image.getColorModel().getPixelSize() / 8;
int width = image.getWidth();
int height = image.getHeight();
int rowWidth = roundToMultipleOfFour(width * pixelBytes);
int maskWidth = roundToMultipleOfFour((width + 7) / 8);
return BITMAPINFOHEADER_SIZE +
(pixelBytes == 1 ? 1024 : 0) +
rowWidth * height +
maskWidth * height;
}
protected int calculateBitDepth(RenderedImage image) {
return image.getColorModel().getPixelSize();
}
protected void writeImage(ImageOutputStream ios, RenderedImage image, Map<Integer, Integer> mappings) throws IOException {
int pixelBytes = image.getColorModel().getPixelSize() / 8;
int width = image.getWidth();
int height = image.getHeight();
int rowWidth = roundToMultipleOfFour(width * pixelBytes);
Raster raster = image.getData();
for (int y = height-1; y >= 0; y--) {
for (int x = 0; x < width; x++) {
if (pixelBytes == 1) {
byte[] dataElements = (byte[]) raster.getDataElements(x, y, null);
int index = mappings.get(((int) dataElements[0]) & 0xFF);
ios.write(index);
} else {
int rgba = image.getColorModel().getRGB(raster.getDataElements(x, y, null));
ios.writeInt(rgba);
}
}
if (pixelBytes == 1)
for (int i = width; i < rowWidth; i++)
ios.write(0);
}
}
protected int calculateHeight(RenderedImage image) {
return super.calculateHeight(image) * 2;
}
protected int calculateSize(RenderedImage image) {
return 0;
}
}