Java tutorial
/* 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); } }