import java.io.File; import java.io.IOException; import java.io.EOFException; import java.io.FileOutputStream; import java.io.RandomAccessFile; import java.awt.Image; import java.awt.Point; import java.awt.Graphics; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.image.Raster; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferByte; import java.awt.image.WritableRaster; import java.awt.image.DirectColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.PixelInterleavedSampleModel; import java.awt.image.SinglePixelPackedSampleModel; import javax.imageio.ImageIO; /** * @author NeedJava * * @version 09.21.2009 */ class ReadICO { private final byte[] buffer = new byte[10485760]; //1024 * 1024 * 10 public ReadICO(){} public void parse( String fileName ) throws IOException { if( fileName == null ){ return; } fileName = fileName.toLowerCase(); if( fileName.endsWith( ".ico" ) || fileName.endsWith( ".cur" ) ) { RandomAccessFile input = new RandomAccessFile( fileName, "r" ); long length = input.length(); if( length > buffer.length ){ System.err.println( "Too large file:" + length ); return; } else{ System.err.println( "Length:[" + length + "]" ); } try{ input.readFully( buffer, 0, buffer.length ); }catch( EOFException e ){} int n = 0; short reserved = readShort( buffer, n ); n += 2; System.err.println( "Reserved:[" + reserved + "]" ); short type = readShort( buffer, n ); n += 2; System.err.println( "Type:[" + type + "]1 is ICO 2 is CUR" ); short count = readShort( buffer, n ); n += 2; System.err.println( "Count:[" + count + "]" ); /// IconDirentry /// for( int i = 0; i < count; i ++ ) { System.err.print( "Icon" + i ); byte width = buffer[n ++]; System.err.print( " width:[" + width + "]" ); //0 if 256 pixels byte height = buffer[n ++]; System.err.print( " height:[" + height + "]" ); //0 if 256 pixels byte colorCount = buffer[n ++]; System.err.print( " colorCount:[" + colorCount + "]" ); //0 if more than 256 colours byte reserverd = buffer[n ++]; System.err.print( " reserverd:[" + reserverd + "]" ); //0 or 255 short colorPlanes = readShort( buffer, n ); n += 2; System.err.print( " colorPlanes:[" + colorPlanes + "]" ); short bitCount = readShort( buffer, n ); n += 2; System.err.print( " bitCount:[" + bitCount + "]" ); //Not correct int size = readInt( buffer, n ); n += 4; System.err.print( " size:[" + size + "]" ); int offset = readInt( buffer, n ); n += 4; System.err.print( " offset:[" + offset + "]/r/n" ); /// IconImage Begin // 1. BitmapInfoHeader / System.err.println( "/t---------- BitmapInfoHeader ----------" ); int temp = offset; //Do not modify this value int infoSize = readInt( buffer, temp ); temp += 4; System.err.println( "/tInfo size(4):" + infoSize ); int imageWidth = readInt( buffer, temp ); temp += 4; System.err.println( "/tWidth(4):" + imageWidth ); int imageHeight = readInt( buffer, temp ); temp += 4; System.err.println( "/tHeight(4):" + imageHeight ); short planes = readShort( buffer, temp ); temp += 2; System.err.println( "/tPlanes(2):" + planes ); short imageBitCount = readShort( buffer, temp ); temp += 2; System.err.println( "/tBit count(2):" + imageBitCount ); int compression = readInt( buffer, temp ); temp += 4; System.err.println( "/tCompression(4):" + compression ); int imageSize = readInt( buffer, temp ); temp += 4; System.err.println( "/tImage size(4):" + imageSize ); int xPels = readInt( buffer, temp ); temp += 4; System.err.println( "/tX pels(4):" + xPels ); int yPels = readInt( buffer, temp ); temp += 4; System.err.println( "/tY pels(4):" + yPels ); int colorUsed = readInt( buffer, temp ); temp += 4; System.err.println( "/tColor used(4):" + colorUsed ); int colorImportant = readInt( buffer, temp ); temp += 4; System.err.println( "/tColor important(4):" + colorImportant ); // 2. ColorTable /// // 3. XorMask // // 4. AndMask // int actualImageHeight = imageHeight / 2; //imageHeight = XorMask height + AndMask height int totalPixels = imageWidth * actualImageHeight; int tableBytes = 0, xorBytes = 0, andBytes = 0; switch( imageBitCount ) { case 1: tableBytes = 2 * 4/*RGBA*/; xorBytes = totalPixels / 8; andBytes = totalPixels / 8; break; //Always 1bit for black/white case 4: tableBytes = 16 * 4/*RGBA*/; xorBytes = totalPixels / 2; andBytes = totalPixels / 8; break; //Always 1bit for black/white case 8: tableBytes = 256 * 4/*RGBA*/; xorBytes = totalPixels; andBytes = totalPixels / 8; break; //Always 1bit for black/white case 16: tableBytes = 0; //No palette for 16 xorBytes = totalPixels * 2; andBytes = totalPixels / 8; break; //Always 1bit for black/white case 24: tableBytes = 0; //No palette for 24 xorBytes = totalPixels * 3; andBytes = totalPixels / 8; break; //Always 1bit for black/white case 32: tableBytes = 0; //No palette for 32 xorBytes = totalPixels * 4; andBytes = totalPixels / 8; break; //Always 1bit for black/white } System.err.println( "/t---------- ColorTable:" + tableBytes + "/tXorMask:" + xorBytes + "/tAndMask:" + andBytes ); /// IconImage End // int bitmapHeaderSize = 14; //BM(2) + Size(4) + Reserved(4) + Offset(4) int bitmapOffset = bitmapHeaderSize + infoSize + tableBytes; int bitmapSize = bitmapHeaderSize + size - andBytes/*infoSize + tableBytes + xorBytes*/; byte[] bytes = new byte[bitmapSize]; System.arraycopy( buffer, offset, bytes, bitmapHeaderSize, bitmapSize - bitmapHeaderSize ); /// Add bitmap file header 14 bytes temp = 0; //We will write bitmap file header to this new buffer from begining writeShort( bytes, 19778/*BM*/, temp ); temp += 2; //Type 'BM' 2 bytes writeInt( bytes, bitmapSize, temp ); temp += 4; //Size 4 bytes writeInt( bytes, 0, temp ); temp += 4; //Reserved 4 bytes writeInt( bytes, bitmapOffset, temp ); temp += 4; //Offset 4 bytes writeInt( bytes, actualImageHeight, bitmapHeaderSize + 4/*infoSize*/ + 4/*imageWidth*/ ); /// Write this bitmap file / writeToBMP( bytes, fileName.substring( 0, fileName.length() - 4 ) + "_" + i + "_" + width + "x" + height + ".bmp" ); } input.close(); } else{ System.err.println( fileName + " is not a ICO or CUR file." ); return; } } private short readShort( byte[] bytes, int offset ) { return (short)( ( ( bytes[offset ++] & 0xFF ) << 0 ) + ( ( bytes[offset ++] & 0xFF ) << 8 ) ); } private int readInt( byte[] bytes, int offset ) { return ( ( ( bytes[offset ++] & 0xFF ) << 0 ) + ( ( bytes[offset ++] & 0xFF ) << 8 ) + ( ( bytes[offset ++] & 0xFF ) << 16 ) + ( ( bytes[offset ++] & 0xFF ) << 24 ) ); } private void writeShort( byte[] bytes, int value, int offset ) { bytes[offset ++] = (byte)( value >> 0 ); bytes[offset ++] = (byte)( value >> 8 ); } private void writeInt( byte[] bytes, int value, int offset ) { bytes[offset ++] = (byte)( value >> 0 ); bytes[offset ++] = (byte)( value >> 8 ); bytes[offset ++] = (byte)( value >> 16 ); bytes[offset ++] = (byte)( value >> 24 ); } public void writeToBMP( byte[] bytes, String fileName ) { try { FileOutputStream output = new FileOutputStream( fileName ); output.write( bytes, 0, bytes.length ); output.close(); } catch( Exception e ){} } public static void main( String[] args ) throws Exception { String[] children = new java.io.File( "." ).list(); if( children == null ){ return; } ReadICO test = new ReadICO(); for( int i = 0; i < children.length; i ++ ) { children[i] = children[i].toLowerCase(); if( children[i].endsWith( ".ico" ) || children[i].endsWith( ".cur" ) ) { System.err.println( "------------------ " + children[i] + " ------------------" ); test.parse( children[i] ); } } } }