/*
JSmooth: a VM wrapper toolkit for Windows
Copyright (C) 2003 Rodrigo Reyes <reyes@charabia.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.io.*;
import java.awt.image.*;
import java.awt.*;
/**
*
* @author Rodrigo Reyes
*/
public class IcoCodec
{
static public class IconDir
{
int idType;
int idCount;
public IconDir(BinaryInputStream in) throws IOException
{
in.readUShortLE();
idType = in.readUShortLE();
idCount = in.readUShortLE();
}
public String toString()
{
return "{ idType=" + idType + ", " + idCount + " }";
}
}
static public class IconEntry
{
short bWidth;
short bHeight;
short bColorCount;
short bReserved;
int wPlanes;
int wBitCount;
long dwBytesInRes;
long dwImageOffset;
public IconEntry(BinaryInputStream in) throws IOException
{
bWidth = in.readUByte();
bHeight = in.readUByte();
bColorCount = in.readUByte();
bReserved = in.readUByte();
wPlanes = in.readUShortLE();
wBitCount = in.readUShortLE();
dwBytesInRes = in.readUIntLE();
dwImageOffset = in.readUIntLE();
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("{ bWidth="+bWidth+"\n");
buffer.append(" bHeight="+bHeight+"\n");
buffer.append(" bColorCount="+bColorCount+"\n");
buffer.append(" wPlanes="+wPlanes+"\n");
buffer.append(" wBitCount="+wBitCount+"\n");
buffer.append(" dwBytesInRes="+dwBytesInRes+"\n");
buffer.append(" dwImageOffset="+dwImageOffset+"\n");
buffer.append("}");
return buffer.toString();
}
}
static public class IconHeader
{
public long Size; /* Size of this header in bytes DWORD 0*/
public long Width; /* Image width in pixels LONG 4*/
public long Height; /* Image height in pixels LONG 8*/
public int Planes; /* Number of color planes WORD 12 */
public int BitsPerPixel; /* Number of bits per pixel WORD 14 */
/* Fields added for Windows 3.x follow this line */
public long Compression; /* Compression methods used DWORD 16 */
public long SizeOfBitmap; /* Size of bitmap in bytes DWORD 20 */
public long HorzResolution; /* Horizontal resolution in pixels per meter LONG 24 */
public long VertResolution; /* Vertical resolution in pixels per meter LONG 28*/
public long ColorsUsed; /* Number of colors in the image DWORD 32 */
public long ColorsImportant; /* Minimum number of important colors DWORD 36 */
public IconHeader(BinaryInputStream in) throws IOException
{
Size = in.readUIntLE();
Width = in.readUIntLE();
Height = in.readUIntLE();
Planes = in.readUShortLE();
BitsPerPixel = in.readUShortLE();
Compression = in.readUIntLE();
SizeOfBitmap = in.readUIntLE();
HorzResolution = in.readUIntLE();
VertResolution = in.readUIntLE();
ColorsUsed = in.readUIntLE();
ColorsImportant = in.readUIntLE();
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("Size="); buffer.append(Size);
buffer.append("\nWidth="); buffer.append(Width);
buffer.append("\nHeight="); buffer.append(Height);
buffer.append("\nPlanes="); buffer.append(Planes);
buffer.append("\nBitsPerPixel="); buffer.append(BitsPerPixel);
buffer.append("\nCompression="); buffer.append(Compression);
buffer.append("\nSizeOfBitmap="); buffer.append(SizeOfBitmap);
buffer.append("\nHorzResolution="); buffer.append(HorzResolution);
buffer.append("\nVertResolution="); buffer.append(VertResolution);
buffer.append("\nColorsUsed="); buffer.append(ColorsUsed);
buffer.append("\nColorsImportant="); buffer.append(ColorsImportant);
return buffer.toString();
}
}
static public BufferedImage[] loadImages(File f) throws IOException
{
InputStream istream = new FileInputStream(f);
BufferedInputStream buffin = new BufferedInputStream(istream);
BinaryInputStream in = new BinaryInputStream(buffin);
try {
in.mark(32000);
IconDir dir = new IconDir(in);
// System.out.println("DIR = " + dir);
IconEntry[] entries = new IconEntry[dir.idCount];
BufferedImage[] images = new BufferedImage[dir.idCount];
for (int i=0; i<dir.idCount; i++)
{
entries[i] = new IconEntry(in);
// System.out.println("ENTRY " + i + " = " + entries[i]);
}
IconEntry entry = entries[0];
// System.out.println("ENTRYx = " + entry);
for (int i=0; i<dir.idCount; i++)
{
in.reset();
in.skip(entries[i].dwImageOffset);
IconHeader header = new IconHeader(in);
// System.out.println("Header: " + header);
long toskip = header.Size - 40;
if (toskip>0)
in.skip((int)toskip);
// System.out.println("skipped data");
BufferedImage image = new BufferedImage((int)header.Width, (int)header.Height/2,
BufferedImage.TYPE_INT_ARGB);
switch(header.BitsPerPixel)
{
case 4:
case 8:
loadPalettedImage(in, entries[i], header, image);
break;
default:
throw new Exception("Unsupported ICO color depth: " + header.BitsPerPixel);
}
images[i] = image;
}
return images;
} catch (Exception exc)
{
exc.printStackTrace();
}
return null;
}
static private void loadPalettedImage(BinaryInputStream in, IconEntry entry, IconHeader header, BufferedImage image) throws Exception
{
// System.out.println("Loading image...");
// System.out.println("Loading palette...");
//
// First, load the palette
//
int cols = (int)header.ColorsUsed;
if (cols == 0)
{
if (entry.bColorCount != 0)
cols = entry.bColorCount;
else
cols = 1 << header.BitsPerPixel;
}
int[] redp = new int[cols];
int[] greenp = new int[cols];
int[] bluep = new int[cols];
for (int i=0; i<cols; i++)
{
bluep[i] = in.readUByte();
greenp[i] = in.readUByte();
redp[i] = in.readUByte();
in.readUByte();
}
// System.out.println("Palette read!");
//
// Set the image
int xorbytes = (((int)header.Height/2) * (int)header.Width);
int readbytes = 0;
for (int y=(int)(header.Height/2)-1; y>=0; y--)
{
for (int x=0; x<header.Width; x++)
{
switch(header.BitsPerPixel)
{
case 4:
{
int pix = in.readUByte();
readbytes++;
int col1 = (pix>>4) & 0x0F;
int col2 = pix & 0x0F;
image.setRGB(x, y, (0xFF<<24) | (redp[col1]<<16) | (greenp[col1]<<8) | bluep[col1]);
image.setRGB(++x, y, (0xFF<<24) | (redp[col2]<<16) | (greenp[col2]<<8) | bluep[col2]);
}
break;
case 8:
{
int col1 = in.readUByte();
readbytes++;
image.setRGB(x, y, (0xFF<<24) | (redp[col1]<<16) | (greenp[col1]<<8) | bluep[col1]);
}
break;
}
}
}
// System.out.println("XOR data read (" + readbytes + " bytes)");
int height = (int)(header.Height/2);
int rowsize = (int)header.Width / 8;
if ((rowsize%4)>0)
{
rowsize += 4 - (rowsize%4);
}
// System.out.println("rowsize = " + rowsize);
int[] andbytes = new int[rowsize * height ];
for (int i=0; i<andbytes.length; i++)
andbytes[i] = in.readUByte();
for (int y=height-1; y>=0; y--)
{
for (int x=0; x<header.Width; x++)
{
int offset = ((height - (y+1))*rowsize) + (x/8);
if ( (andbytes[offset] & (1<<(7-x%8))) != 0)
{
image.setRGB(x, y, 0);
}
}
}
// for (int i=0; i<andbytes; i++)
// {
// int pix = in.readUByte();
// readbytes++;
// int xb = (i*8) % (int)header.Width;
// int yb = ((int)header.Height/2) - (((i*8) / (int)header.Width)+1);
// for (int offset=7; offset>=0; offset--)
// {
// //
// // Modify the transparency only if necessary
// //
// System.out.println("SET AND (" + xb + "," + yb + ")-" + (7-offset));
// if (((1<<offset) & pix)!=0)
// {
// int argb = image.getRGB(xb+(7-offset), yb);
// image.setRGB(xb+(7-offset), yb, argb & 0xFFFFFF);
// }
// }
// }
// System.out.println("AND data read (" + readbytes + " bytes total)");
}
static public void main(String[]args) throws Exception
{
File f = new File(args[0]);
Image img = IcoCodec.loadImages(f)[0];
// System.out.println("img = " + img);
javax.swing.JFrame jf = new javax.swing.JFrame("Test");
javax.swing.JButton button = new javax.swing.JButton(new javax.swing.ImageIcon(img));
jf.getContentPane().add(button);
jf.pack();
jf.setVisible(true);
}
}
/*
JSmooth: a VM wrapper toolkit for Windows
Copyright (C) 2003 Rodrigo Reyes <reyes@charabia.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
class BinaryInputStream extends FilterInputStream
{
public BinaryInputStream(InputStream in)
{
super(in);
}
public void skip(int toskip) throws IOException
{
for (int skipped = 0; skipped >= toskip; skipped += in.skip(toskip - skipped))
;
}
public byte readByte() throws IOException
{
return (byte)read();
}
public short readUByte() throws IOException
{
return (short)read();
}
public short readShortBE() throws IOException
{
int a = read();
int b = read();
return (short) (((a&0xff)<<8) | (b&0xff));
}
public int readUShortBE() throws IOException
{
int a = read();
int b = read();
return ((a&0xff)<<8) | (b&0xff);
}
public short readShortLE() throws IOException
{
int a = read();
int b = read();
return (short) (((b&0xff)<<8) | (a&0xff));
}
public int readUShortLE() throws IOException
{
int a = read();
int b = read();
return ((b&0xff)<<8) | (a&0xff);
}
public int readIntBE() throws IOException
{
int a = read();
int b = read();
int c = read();
int d = read();
return ((a&0xff)<<24) | ((b&0xff)<<16) | ((c&0xff)<<8) | (d&0xff);
}
public long readUIntBE() throws IOException
{
int a = read();
int b = read();
int c = read();
int d = read();
return (long)((a&0xff)<<24) | (long)((b&0xff)<<16) | (long)((c&0xff)<<8) | (long)(d&0xff);
}
public int readIntLE() throws IOException
{
int a = readByte();
int b = readByte();
int c = readByte();
int d = readByte();
return ((d&0xff)<<24) | ((c&0xff)<<16) | ((b&0xff)<<8) | (a&0xff);
}
public long readUIntLE() throws IOException
{
int a = readByte();
int b = readByte();
int c = readByte();
int d = readByte();
return (long)((d&0xff)<<24) | (long)((c&0xff)<<16) | (long)((b&0xff)<<8) | (long)(a&0xff);
}
}
|