32bit icon jsmooth patch with alpha channel support

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@135 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2008-09-30 22:35:01 +00:00
parent ae8ca73c50
commit b65e64c474
5 changed files with 1611 additions and 0 deletions

View File

@ -0,0 +1,506 @@
/*
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.
*/
package net.charabia.jsmoothgen.application;
import net.charabia.jsmoothgen.skeleton.*;
import net.charabia.jsmoothgen.pe.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.lang.reflect.*;
import net.charabia.util.codec.*;
import javax.imageio.ImageIO;
public class ExeCompiler
{
private java.util.Vector m_errors = new java.util.Vector();
private Vector m_listeners = new Vector();
public interface StepListener
{
public void setNewState(int percentComplete, String state);
public void failed();
public void complete();
}
public void addListener(ExeCompiler.StepListener listener)
{
m_listeners.add(listener);
}
public void cleanErrors()
{
m_errors.removeAllElements();
}
public java.util.Vector getErrors()
{
return m_errors;
}
public class CompilerRunner implements Runnable
{
private File m_skelroot;
private SkeletonBean m_skel;
private JSmoothModelBean m_data;
private File m_out;
private File m_basedir;
public CompilerRunner(File skelroot, SkeletonBean skel, File basedir, JSmoothModelBean data, File out)
{
m_skelroot = skelroot;
m_skel = skel;
m_data = data;
m_out = out;
m_basedir = basedir;
}
public void run()
{
try
{
compile(m_skelroot, m_skel, m_basedir, m_data, m_out);
} catch (Exception exc)
{
exc.printStackTrace();
}
}
public ExeCompiler getCompiler()
{
return ExeCompiler.this;
}
}
public ExeCompiler.CompilerRunner getRunnable(File skelroot, SkeletonBean skel, File basedir, JSmoothModelBean data, File out)
{
return new CompilerRunner(skelroot, skel, basedir, data, out);
}
public void compileAsync(File skelroot, SkeletonBean skel, File basedir, JSmoothModelBean data, File out)
{
Thread t = new Thread(new CompilerRunner(skelroot, skel, basedir, data, out));
t.start();
}
public boolean compile(File skelroot, SkeletonBean skel, File basedir ,JSmoothModelBean data, File out) throws Exception
{
try {
fireStepChange(0, "Starting compilation");
File pattern = new File(skelroot, skel.getExecutableName());
if (pattern.exists() == false)
{
m_errors.add("Error: Can't find any skeleton at " + skelroot);
fireFailedChange();
return false;
}
fireStepChange(10, "Scanning skeleton...");
PEFile pe = new PEFile(pattern);
pe.open();
PEResourceDirectory resdir = pe.getResourceDirectory();
boolean resb = false;
//
// Adds the jar only if the user selected one
//
if (data.getEmbeddedJar() == true)
{
if (data.getJarLocation() == null)
{
m_errors.add("Error: Jar is not specified!");
fireFailedChange();
return false;
}
fireStepChange(40, "Loading Jar...");
File jarloc = concFile(basedir, new File(data.getJarLocation()));
if (jarloc.exists() == false)
{
m_errors.add("Error: Can't find jar at " + jarloc);
fireFailedChange();
return false;
}
ByteBuffer jardata = load(jarloc);
fireStepChange(60, "Adding Jar to Resources...");
resb = resdir.replaceResource(skel.getResourceCategory(), skel.getResourceJarId(), 1033, jardata);
if (resb == false)
{
m_errors.add("Error: Can't replace jar resource! It is probably missing from the skeleton.");
fireFailedChange();
return false;
}
}
fireStepChange(70, "Adding Properties to Resources...");
String props = PropertiesBuilder.makeProperties(basedir, data);
ByteBuffer propdata = convert(props);
resb = resdir.replaceResource(skel.getResourceCategory(), skel.getResourcePropsId(), 1033, propdata);
if (data.getIconLocation() != null)
{
fireStepChange(80, "Loading icon...");
String iconpath;
if (new java.io.File(data.getIconLocation()).isAbsolute())
iconpath = data.getIconLocation();
else
iconpath = new java.io.File(basedir, data.getIconLocation()).getAbsolutePath();
Image img = getScaledImage(iconpath, 32, 32);
//Hashtable set = calculateColorCount(img);
// System.out.println("COLORS TOTAL 4: " + set.size());
if (img != null)
{
net.charabia.jsmoothgen.pe.res.ResIcon32 resicon = new net.charabia.jsmoothgen.pe.res.ResIcon32(img);
pe.replaceDefaultIcon(resicon);
}
}
fireStepChange(90, "Saving exe...");
pe.dumpTo(out);
// System.out.println("PROPERTIES:\n" + props);
fireCompleteChange();
return true;
} catch (Exception exc)
{
m_errors.add("Error: " + exc.getMessage());
exc.printStackTrace();
fireFailedChange();
return false;
}
}
public Image[] loadImages(String path)
{
File f = new File(path);
if (path.toUpperCase().endsWith(".ICO"))
{
//
// Try to load with our ico codec...
//
try {
java.awt.Image[] images = net.charabia.util.codec.IcoCodec.loadImages(f);
if ((images != null) && (images.length>0))
{
return images;
}
} catch (java.io.IOException exc)
{
exc.printStackTrace();
}
}
//
// defaults to the standard java loading process
//
BufferedImage bufferedImage;
try {
bufferedImage = ImageIO.read(f);
javax.swing.ImageIcon icon = new javax.swing.ImageIcon(bufferedImage, "default icon");
java.awt.Image[] imgs = new java.awt.Image[1];
imgs[0] = icon.getImage();
return imgs;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void checkImageLoaded(Image img)
{
MediaTracker mtrack = new MediaTracker(new Canvas());
mtrack.addImage(img, 1);
try {
mtrack.waitForAll();
} catch (InterruptedException e) {
}
}
private Hashtable calculateColorCount(Image img)
{
int width = img.getWidth(null);
int height = img.getHeight(null);
int[] pixels = new int[width*height];
PixelGrabber grabber = new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
try
{
grabber.grabPixels();
} catch (InterruptedException e)
{
System.err.println("interrupted waiting for pixels!");
// throw new Exception("Can't load the image provided",e);
}
Hashtable result = new Hashtable();
int colorindex = 0;
for (int i=0; i<pixels.length; i++)
{
int pix = pixels[i];
if (((pix>>24)&0xFF) > 0)
{
pix &= 0x00FFFFFF;
Integer pixi = new Integer(pix);
Object o = result.get(pixi);
if (o == null)
{
result.put(pixi, new Integer(colorindex++));
}
// if (colorindex > 256)
// return result;
}
}
return result;
}
public BufferedImage getQuantizedImage(Image img)
{
// 32 bit ico file already loaded as BufferedImage
if (img instanceof BufferedImage) {
return (BufferedImage) img;
} else {
int width = img.getWidth(null);
int height = img.getHeight(null);
int[][] data = new int[width][height];
int[] pixelbuffer = new int[width*height];
PixelGrabber grabber = new PixelGrabber(img, 0, 0, width, height, pixelbuffer, 0, width);
try
{
grabber.grabPixels();
} catch (InterruptedException e)
{
System.err.println("interrupted waiting for pixels!");
throw new RuntimeException("Can't load the image provided",e);
}
for (int i=0; i<pixelbuffer.length; i++)
{
data[i%width][i/width] = pixelbuffer[i];
}
int[][] savedata = new int[width][height];
for(int y=0;y<height;y++)
for (int x=0;x<width;x++)
savedata[x][y] = data[x][y];
int[] palette = net.charabia.util.codec.Quantize.quantizeImage(data, 255);
byte[] cmap = new byte[256*4];
for (int i=0; i<palette.length; i++)
{
// System.out.println(" i= " + (i));
cmap[(i*4)] = (byte)((palette[i] >> 16) & 0xFF);
cmap[(i*4)+1] = (byte)((palette[i] >> 8) & 0xFF);
cmap[(i*4)+2] = (byte) (palette[i] & 0xFF);
cmap[(i*4)+3] = (byte) 0xFF;
}
IndexColorModel colmodel = new IndexColorModel(8, palette.length, cmap, 0, true, 0);
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//
// The normal manner of quantizing would be to run
// result.setRGB(0,0, width, height, pixelbuffer, 0, width);
// where result is a BufferedImage of
// BufferedImage.TYPE_BYTE_INDEXED type. Unfortunately, I
// couldn't make it work. So, here is a work-around that
// should work similarly.
//
java.util.Hashtable set = new java.util.Hashtable();
for (int y=0; y<height; y++)
{
for (int x=0; x<width; x++)
{
int alpha = (savedata[x][y]>>24)&0xFF;
if (alpha == 0)
{
result.setRGB(x,y, 0);
// System.out.print(".");
}
else
{
int rgb = colmodel.getRGB(data[x][y]);
rgb |= 0xFF000000;
set.put(new Integer(rgb), new Integer(rgb));
result.setRGB(x,y,rgb);
// System.out.print("*");
}
}
// System.out.println("");
}
return result;
}
}
public Image checkImageSize(Image img, int width, int height)
{
int w = img.getWidth(null);
int h = img.getHeight(null);
if ((w == width) && (h == height))
return img;
return null;
}
public Image getScaledImage(String path, int width, int height)
{
Image[] orgimages = loadImages(path);
if ((orgimages == null) || (orgimages.length == 0))
return null;
for (int i=0; i<orgimages.length; i++)
checkImageLoaded(orgimages[i]);
// System.out.println("Loaded " + orgimages.length + " images");
for (int i=0; (i<orgimages.length); i++)
{
int w = orgimages[i].getWidth(null);
int h = orgimages[i].getHeight(null);
// System.out.println("Size of " + i + " = " + w + "," + h);
}
//
// We prefer 32x32 pictures, then 64x64, then 16x16...
//
Image selected = null;
for (int i=0; (i<orgimages.length) && (selected==null); i++)
selected = checkImageSize(orgimages[i], 32, 32);
for (int i=0; (i<orgimages.length) && (selected==null); i++)
selected = checkImageSize(orgimages[i], 64, 64);
for (int i=0; (i<orgimages.length) && (selected==null); i++)
selected = checkImageSize(orgimages[i], 16, 16);
if (selected != null)
{
return getQuantizedImage(selected);
}
//
// If there is no 32x32, 64x64, nor 16x16, then we scale the
// biggest image to be 32x32... This should happen mainly when
// loading an image from a png of gif file, and in most case
// there is only one image on the array.
//
int maxsize = 0;
Image biggest = null;
for (int i=0; (i<orgimages.length) && (selected==null); i++)
{
int size = orgimages[i].getWidth(null) * orgimages[i].getHeight(null);
if (size>maxsize)
{
maxsize = size;
biggest = orgimages[i];
}
}
if (biggest != null)
{
Image result = biggest.getScaledInstance(32, 32, Image.SCALE_AREA_AVERAGING);
checkImageLoaded(result);
return getQuantizedImage(result);
}
//
// Here, we have failed and return null
//
return null;
}
private ByteBuffer load(File in) throws Exception
{
FileInputStream fis = new FileInputStream(in);
ByteBuffer data = ByteBuffer.allocate((int)in.length());
data.order(ByteOrder.LITTLE_ENDIAN);
FileChannel fischan = fis.getChannel();
fischan.read(data);
data.position(0);
fis.close();
return data;
}
private ByteBuffer convert(String data)
{
ByteBuffer result = ByteBuffer.allocate(data.length()+1);
result.position(0);
for (int i=0; i<data.length(); i++)
{
result.put((byte)data.charAt(i));
}
result.put((byte)0);
result.position(0);
return result;
}
static public File concFile(File root, File name)
{
if (name.isAbsolute())
return name;
return new File(root, name.toString());
}
public void fireStepChange(int percentComplete, String state)
{
for (Iterator i=m_listeners.iterator(); i.hasNext(); )
{
ExeCompiler.StepListener l = (ExeCompiler.StepListener)i.next();
l.setNewState(percentComplete, state);
}
}
public void fireFailedChange()
{
for (Iterator i=m_listeners.iterator(); i.hasNext(); )
{
ExeCompiler.StepListener l = (ExeCompiler.StepListener)i.next();
l.failed();
}
}
public void fireCompleteChange()
{
for (Iterator i=m_listeners.iterator(); i.hasNext(); )
{
ExeCompiler.StepListener l = (ExeCompiler.StepListener)i.next();
l.complete();
}
}
}

View File

@ -0,0 +1,160 @@
/*
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.
*/
package net.charabia.jsmoothgen.application.gui.editors;
import net.charabia.jsmoothgen.skeleton.*;
import net.charabia.jsmoothgen.application.*;
import net.charabia.jsmoothgen.application.gui.*;
import net.charabia.jsmoothgen.application.gui.util.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;
import java.io.*;
import com.l2fprod.common.swing.*;
import com.l2fprod.common.propertysheet.*;
public class ExecutableIcon extends Editor
{
private FileSelectionTextField m_selector = new FileSelectionTextField();
private JLabel m_iconDisplay = new JLabel("(no image)");
public ExecutableIcon()
{
setLayout(new BorderLayout());
add(BorderLayout.CENTER, m_selector);
add(BorderLayout.SOUTH, m_iconDisplay);
m_iconDisplay.setHorizontalAlignment(JLabel.CENTER);
m_selector.addListener(new FileSelectionTextField.FileSelected() {
public void fileSelected(String filename)
{
// System.out.println("new icon: " + filename);
setIconLocation(new File(filename));
}
});
}
public void dataChanged()
{
if (getBaseDir() != null)
m_selector.setBaseDir(getBaseDir());
if (m_model.getIconLocation() != null)
{
m_selector.setFile(getAbsolutePath(new java.io.File(m_model.getIconLocation())));
setIconLocation(getAbsolutePath(new java.io.File(m_model.getIconLocation())));
}
else
{
m_selector.setFile(null);
setIconLocation(new File(""));
}
}
public void updateModel()
{
File f = m_selector.getFile();
if (f != null)
m_model.setIconLocation(m_selector.getFile().toString());
else
m_model.setIconLocation(null);
}
public String getLabel()
{
return "ICONLOCATION_LABEL";
}
public String getDescription()
{
return "ICONLOCATION_HELP";
}
private void setIconLocation(File iconfile)
{
if (iconfile.isAbsolute() == false)
{
iconfile = new File(m_basedir, iconfile.toString());
}
ImageIcon icon = null;
// System.out.println("setIconLocation: " + iconfile);
if (iconfile.toString().toUpperCase().endsWith(".ICO"))
{
//
// Try to load with our ico codec...
//
try {
java.awt.image.BufferedImage[] images = net.charabia.util.codec.IcoCodec.loadImages(iconfile);
if ((images != null) && (images.length>0))
{
java.awt.Image img = images[0];
icon = new ImageIcon(img);
}
} catch (java.io.IOException exc)
{
exc.printStackTrace();
}
}
else // Otherwise try with the standard toolkit functions...
{
BufferedImage bufferedImage;
try {
bufferedImage = ImageIO.read(iconfile);
icon = new javax.swing.ImageIcon(bufferedImage, "default icon");
} catch (IOException e) {
e.printStackTrace();
}
}
if (icon != null)
{
int width = icon.getIconWidth();
int height = icon.getIconHeight();
m_iconDisplay.setIcon(icon);
m_iconDisplay.setText("");
m_model.setIconLocation(iconfile.getAbsolutePath());
this.validate();
this.invalidate();
}
else
{
m_iconDisplay.setIcon(null);
m_iconDisplay.setText("(no image)");
m_model.setIconLocation(null);
}
doLayout();
invalidate();
validate();
repaint();
}
}

View File

@ -0,0 +1,462 @@
/*
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.
*/
/*
* ResIcon.java
*
* Created on 17 août 2003, 22:51
*/
package net.charabia.jsmoothgen.pe.res;
import java.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.awt.*;
import java.awt.image.*;
/**
* @see
*/
public class ResIcon
{
public long Size; /* Size of this header in bytes DWORD*/
public long Width; /* Image width in pixels LONG*/
public long Height; /* Image height in pixels LONG*/
public int Planes; /* Number of color planes WORD*/
public int BitsPerPixel; /* Number of bits per pixel WORD*/
/* Fields added for Windows 3.x follow this line */
public long Compression; /* Compression methods used DWORD*/
public long SizeOfBitmap; /* Size of bitmap in bytes DWORD*/
public long HorzResolution; /* Horizontal resolution in pixels per meter LONG*/
public long VertResolution; /* Vertical resolution in pixels per meter LONG*/
public long ColorsUsed; /* Number of colors in the image DWORD*/
public long ColorsImportant; /* Minimum number of important colors DWORD*/
public PaletteElement[] Palette;
public short[] BitmapXOR;
public short[] BitmapAND;
public class PaletteElement
{
public int Blue;
public int Green;
public int Red;
public int Reserved;
public String toString()
{
return "{"+Blue+","+Green+","+Red+","+Reserved+"}";
}
}
public ResIcon(){};
/**
* Creates a new instance of ResIcon
* @see
* @param in
*/
public ResIcon(ByteBuffer in)
{
Size = in.getInt();
Width = in.getInt();
Height = in.getInt();
Planes = in.getShort();
BitsPerPixel = in.getShort();
Compression = in.getInt();
SizeOfBitmap = in.getInt();
HorzResolution = in.getInt();
VertResolution = in.getInt();
ColorsUsed = in.getInt();
ColorsImportant = in.getInt();
int cols = (int)ColorsUsed;
if (cols == 0)
cols = 1 << BitsPerPixel;
Palette = new PaletteElement[(int)cols];
for (int i=0; i<Palette.length; i++)
{
PaletteElement el = new PaletteElement();
el.Blue = in.get();
el.Green = in.get();
el.Red = in.get();
el.Reserved = in.get();
Palette[i] = el;
}
// int xorbytes = (((int)Height/2) * (int)Width * (int)BitsPerPixel) / 8;
int xorbytes = (((int)Height/2) * (int)Width);
// System.out.println("POSITION " + in.position() + " : xorbitmap = " + xorbytes + " bytes");
BitmapXOR = new short[xorbytes];
for (int i=0; i<BitmapXOR.length; i++)
{
switch(BitsPerPixel)
{
case 4:
{
int pix = in.get();
BitmapXOR[i] = (short)((pix >> 4) & 0x0F);
i++;
BitmapXOR[i] = (short)(pix & 0x0F);
}
break;
case 8:
{
BitmapXOR[i] = in.get();
}
break;
}
}
int height = (int)(Height/2);
int rowsize = (int)Width / 8;
if ((rowsize%4)>0)
{
rowsize += 4 - (rowsize%4);
}
// System.out.println("POSITION " + in.position() + " : andbitmap = " + andbytes + " bytes");
int andbytes = height * rowsize; // (((int)Height/2) * (int)Width) / 8;
BitmapAND = new short[andbytes];
for (int i=0; i<BitmapAND.length; i++)
{
BitmapAND[i] = in.get();
}
}
/** Creates a new instance based on the data of the Image argument.
* @param img
*/
public ResIcon(Image img) throws Exception
{
int width = img.getWidth(null);
int height = img.getHeight(null);
if ((width % 8) != 0)
width += (7-(width%8));
if ((height % 8) != 0)
height += (7-(height%8));
// System.out.println("FOUND WIDTH " + width + " (was " + img.getWidth(null) + ")");
// System.out.println("FOUND HEIGHT " + height + " (was " + img.getHeight(null) + ")");
// System.out.println("RESICON...");
if (img instanceof BufferedImage)
{
BufferedImage result = (BufferedImage)img;
for (int y=0; y<result.getHeight(); y++)
{
for (int x=0; x<result.getWidth(); x++)
{
int rgb = result.getRGB(x, y);
if (((rgb>>24)&0xFF)>0)
{
// System.out.print(".");
}
// else
// System.out.print("*");
}
// System.out.println("");
}
}
int[] pixelbuffer = new int[width*height];
PixelGrabber grabber = new PixelGrabber(img, 0, 0, width, height, pixelbuffer, 0, width);
try
{
grabber.grabPixels();
} catch (InterruptedException e)
{
System.err.println("interrupted waiting for pixels!");
throw new Exception("Can't load the image provided",e);
}
Hashtable colors = calculateColorCount(pixelbuffer);
// FORCE ALWAYS to 8
this.BitsPerPixel = 8;
Palette = new ResIcon.PaletteElement[1 << BitsPerPixel];
// System.out.println("Creating palette of " + Palette.length + " colors (" + colors.size() + ")");
for (Enumeration e=colors.keys(); e.hasMoreElements(); )
{
Integer pixi = (Integer)e.nextElement();
int pix = pixi.intValue();
int index = ((Integer)colors.get(pixi)).intValue();
// System.out.println("set pixel " + index);
Palette[index] = new ResIcon.PaletteElement();
Palette[index].Blue = pix & 0xFF;
Palette[index].Green = (pix >> 8) & 0xff;
Palette[index].Red = (pix >> 16) & 0xff;
}
for (int i=0; i<Palette.length; i++)
{
if (Palette[i] == null)
Palette[i] = new ResIcon.PaletteElement();
}
this.Size = 40;
this.Width = width;
this.Height = height* 2;
this.Planes = 1;
this.Compression = 0;
this.SizeOfBitmap = 0;
this.HorzResolution = 0;
this.VertResolution = 0;
this.ColorsUsed = 0;
this.ColorsImportant = 0;
//
// We calculate the rowsize in bytes. It seems that it must be
// aligned on a double word, although none of the
// documentation I have on the icon format states so.
//
int rowsize = width / 8;
if ((rowsize%4)>0)
{
rowsize += 4 - (rowsize%4);
}
BitmapXOR = new short[(((int)Height/2) * (int)Width * (int)BitsPerPixel) / 8];
BitmapAND = new short[((int)Height/2) * rowsize];
int bxl = BitmapXOR.length-1;
int bal = BitmapAND.length-1;
for (int i=0; i<pixelbuffer.length; i++)
{
int col = i%width;
int line = i/width;
bxl = (width * height) - (((i/width)+1)*width) + (i%width);
// bal = ((width * height)/8) - ((line+1)*(width/8)) + (col/8);
bal = (rowsize * height) - ((line+1)*(rowsize)) + (col/8);
// if ((pixelbuffer[i] & 0xFF000000) != 0x00000000)
//
// If the color is transparent, any color will suit
// (as it is not supposed to be displayed)
//
if ( (((pixelbuffer[i]>>24)& 0xFF) == 0))
{
BitmapAND[ bal ] |= 1 << (7-(i%8));
BitmapXOR[bxl] = 0xFF; // (short)getBrightest(); FF
// int pixel = pixelbuffer[i] & 0x00FFFFFF;
// pixel = 0x000000;
// Integer icol = (Integer)colors.get(new Integer(pixel));
// if (icol != null)
// {
// int palindex = icol.intValue();
// BitmapXOR[bxl] = (short)palindex;
// }
// else
// {
// BitmapXOR[bxl] = 0; // (short)getBrightest();
// System.out.println("Can't find TRANSP BLACK COL " + icol );
// }
}
else
{
int pixel = pixelbuffer[i] & 0x00FFFFFF;
// pixel = 0x000000;
Integer icol = (Integer)colors.get(new Integer(pixel));
if (icol != null)
{
int palindex = icol.intValue();
BitmapXOR[bxl] = (short)palindex;
}
}
}
}
private int getBrightest()
{
int result = 0;
int averesult = 0;
for (int i=0; i<Palette.length; i++)
{
int ave1 = (Palette[0].Red + Palette[0].Green + Palette[0].Blue)/3;
if (ave1 > averesult)
{
averesult = ave1;
result = i;
}
}
return result;
}
private Hashtable calculateColorCount(int[] pixels)
{
Hashtable result = new Hashtable();
int colorindex = 0;
for (int i=0; i<pixels.length; i++)
{
int pix = pixels[i];
if (((pix>>24)&0xFF) > 0)
{
pix &= 0x00FFFFFF;
Integer pixi = new Integer(pix);
Object o = result.get(pixi);
if (o == null)
{
result.put(pixi, new Integer(colorindex++));
}
// if (colorindex > 256)
// return result;
}
}
return result;
}
/** Creates and returns a ByteBuffer containing an image under
* the .ico format expected by Windows.
* @return a ByteBuffer with the .ico data
*/
public ByteBuffer getData()
{
int cols = (int)ColorsUsed;
if (cols == 0)
cols = 1 << BitsPerPixel;
int rowsize = (int)Width / 8;
if ((rowsize%4)>0)
{
rowsize += 4 - (rowsize%4);
}
ByteBuffer buf = ByteBuffer.allocate((int) (40 + (cols*4) + (Width*(Height/2)*BitsPerPixel)/8 + (rowsize*(Height/2))));
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.position(0);
buf.putInt((int)Size);
buf.putInt((int)Width);
buf.putInt((int)Height);
buf.putShort((short)Planes);
buf.putShort((short)BitsPerPixel);
buf.putInt((int)Compression);
buf.putInt((int)SizeOfBitmap);
buf.putInt((int)HorzResolution);
buf.putInt((int)VertResolution);
buf.putInt((int)ColorsUsed);
buf.putInt((int)ColorsImportant);
// System.out.println("GET DATA :: Palette.size= "+Palette.length + " // position=" + buf.position());
for (int i=0; i<Palette.length; i++)
{
PaletteElement el = Palette[i];
buf.put((byte)el.Blue);
buf.put((byte)el.Green);
buf.put((byte)el.Red);
buf.put((byte)el.Reserved);
}
switch (BitsPerPixel)
{
case 4:
{
for (int i=0; i<BitmapXOR.length; i+=2)
{
int v1 = BitmapXOR[i];
int v2 = BitmapXOR[i+1];
buf.put((byte)( (v1<<4) | v2 ));
}
}
break;
case 8:
{
// System.out.println("GET DATA :: XORBitmap.size= "+BitmapXOR.length + " // position=" + buf.position());
for (int i=0; i<BitmapXOR.length; i++)
{
buf.put((byte)BitmapXOR[i]);
}
}
break;
default:
throw new RuntimeException("BitRes " + BitsPerPixel + " not supported!");
}
// System.out.println("GET DATA :: AndBitmap.size= "+BitmapAND.length + " // position=" + buf.position());
for (int i=0; i<BitmapAND.length; i++)
{
buf.put((byte)BitmapAND[i]);
}
// System.out.println("GET DATA END AT " + buf.position());
buf.position(0);
return buf;
}
public String toString()
{
StringBuffer out = new StringBuffer();
out.append("Size: " + Size);
out.append("\nWidth: " + Width);
out.append("\nHeight: " + Height);
out.append("\nPlanes: " + Planes);
out.append("\nBitsPerPixel: " + BitsPerPixel);
out.append("\nCompression: " + Compression);
out.append("\nSizeOfBitmap: " + SizeOfBitmap);
out.append("\nHorzResolution: " + HorzResolution);
out.append("\nVertResolution: " + VertResolution);
out.append("\nColorsUsed: " + ColorsUsed);
out.append("\nColorsImportant: " + ColorsImportant);
// for (int i = 0; i<Palette.length; i++)
// {
// out.append("\n");
// out.append(Palette[i].toString());
// }
out.append("\nBitmapXOR["+ BitmapXOR.length+ "]={");
for (int i=0; i<BitmapXOR.length; i++)
{
out.append((byte)BitmapXOR[i]);
}
out.append("}\nBitmapAnd["+ BitmapAND.length +"]={");
for (int i=0; i<BitmapAND.length; i++)
{
out.append((byte)BitmapAND[i]);
}
return out.toString();
}
public static void main(String[]args) throws Exception
{
net.charabia.jsmoothgen.pe.PEFile.main(args);
}
}

View File

@ -0,0 +1,126 @@
package net.charabia.jsmoothgen.pe.res;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* 32 bits res icon with alpha channel
*/
public class ResIcon32 extends ResIcon {
BufferedImage image;
/**
* Creates a new instance based on the data of the Image argument.
*
* @param img image
* @throws Exception on error
*/
public ResIcon32(Image img) throws Exception {
int width = img.getWidth(null);
int height = img.getHeight(null);
image = (BufferedImage) img;
this.BitsPerPixel = 32;
// header size
this.Size = 40;
this.Width = width;
this.Height = height * 2;
this.Planes = 1;
this.Compression = 0;
this.SizeOfBitmap = 0;
this.HorzResolution = 0;
this.VertResolution = 0;
this.ColorsUsed = 0;
this.ColorsImportant = 0;
}
/**
* Creates and returns a ByteBuffer containing an image under
* the .ico format expected by Windows.
*
* @return a ByteBuffer with the .ico data
*/
public ByteBuffer getData() {
// transparency mask rows must be double bytes aligned
int rowsize = (int) Width / 8;
int padding = 0;
if ((rowsize % 4) > 0) {
padding = (int) ((4 - Width / 8 % 4) * 8);
rowsize += 4 - (rowsize % 4);
}
// transparency line padding size
// create transparency mask buffer
int transparencyBytesSize = (int) (rowsize * (Height / 2));
int[] transparencyMask = new int[transparencyBytesSize];
// allocate header + pixel count * bytes / pixel + transparency mask size
ByteBuffer buf = ByteBuffer.allocate((int) (40 + (Width * ((Height) / 2) * BitsPerPixel/8) + transparencyBytesSize));
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.position(0);
// write header
buf.putInt((int) Size);
buf.putInt((int) Width);
buf.putInt((int) Height);
buf.putShort((short) Planes);
buf.putShort((short) BitsPerPixel);
buf.putInt((int) Compression);
buf.putInt((int) SizeOfBitmap);
buf.putInt((int) HorzResolution);
buf.putInt((int) VertResolution);
buf.putInt((int) ColorsUsed);
buf.putInt((int) ColorsImportant);
int pixelCount = 0;
for (int y = (int) ((Height / 2) - 1); y >= 0; y--) {
for (int x = 0; x < Width; x++) {
int pix = image.getRGB(x, y);
//System.out.println(x+" "+y+":"+Integer.toHexString((pix >> 24) & 0xff));
boolean isTransparent = ((pix >> 24) & 0xff) == 0;
if (isTransparent) {
int index = pixelCount / 8;
byte bitindex = (byte) (pixelCount % 8);
transparencyMask[index] |= 0x80 >> bitindex;
}
buf.putInt(pix);
pixelCount++;
}
// skip to next transparency line
pixelCount += padding;
}
// transparency mask
for (int x = 0; x < transparencyBytesSize; x++) {
buf.put((byte) (transparencyMask[x] & 0xff));
}
buf.position(0);
return buf;
}
public String toString() {
StringBuffer out = new StringBuffer();
out.append("Size: ").append(Size);
out.append("\nWidth: ").append(Width);
out.append("\nHeight: ").append(Height);
out.append("\nPlanes: ").append(Planes);
out.append("\nBitsPerPixel: ").append(BitsPerPixel);
out.append("\nCompression: ").append(Compression);
out.append("\nSizeOfBitmap: ").append(SizeOfBitmap);
out.append("\nHorzResolution: ").append(HorzResolution);
out.append("\nVertResolution: ").append(VertResolution);
out.append("\nColorsUsed: ").append(ColorsUsed);
out.append("\nColorsImportant: ").append(ColorsImportant);
return out.toString();
}
}

View File

@ -0,0 +1,357 @@
/*
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.
*/
package net.charabia.util.codec;
import java.io.*;
import net.charabia.util.io.BinaryInputStream;
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;
case 32:
load32bitsImage(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 private void load32bitsImage(BinaryInputStream in, IconEntry entry, IconHeader header, BufferedImage image) throws Exception {
for (int y = (int) ((header.Height) / 2) - 1; y >= 0; y--) {
for (int x = 0; x < header.Width; x++) {
byte alpha = in.readByte();
byte red = in.readByte();
byte green = in.readByte();
byte blue = in.readByte();
int pix = (alpha &0xff) | (red &0xff) <<8 | (green &0xff) << 16 | (blue &0xff) << 24;
image.setRGB(x, y, pix);
}
}
}
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);
}
}