mirror of
https://github.com/moparisthebest/davmail
synced 2025-01-06 03:08:02 -05:00
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:
parent
ae8ca73c50
commit
b65e64c474
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
357
jsmooth-0.9.9-7-patch/src/net/charabia/util/codec/IcoCodec.java
Normal file
357
jsmooth-0.9.9-7-patch/src/net/charabia/util/codec/IcoCodec.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user