2D Graphics GUI Java

/*
  JSmooth: a VM wrapper toolkit for Windows
  Copyright (C) 2003 Rodrigo Reyes 
 
  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    {
        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    {
        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      {
    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        {
      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[i] = in.readUByte();
  for (int y=height-1; y>=0; y--)
      {
    for (int x=0; 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  //      {
  //    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<  //          {
  //        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 
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);
  }
}