From b65e64c474394a2f4de58f9ef508ed755ac80cc3 Mon Sep 17 00:00:00 2001 From: mguessan Date: Tue, 30 Sep 2008 22:35:01 +0000 Subject: [PATCH] 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 --- .../jsmoothgen/application/ExeCompiler.java | 506 ++++++++++++++++++ .../gui/editors/ExecutableIcon.java | 160 ++++++ .../charabia/jsmoothgen/pe/res/ResIcon.java | 462 ++++++++++++++++ .../charabia/jsmoothgen/pe/res/ResIcon32.java | 126 +++++ .../src/net/charabia/util/codec/IcoCodec.java | 357 ++++++++++++ 5 files changed, 1611 insertions(+) create mode 100644 jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/application/ExeCompiler.java create mode 100644 jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/application/gui/editors/ExecutableIcon.java create mode 100644 jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/pe/res/ResIcon.java create mode 100644 jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/pe/res/ResIcon32.java create mode 100644 jsmooth-0.9.9-7-patch/src/net/charabia/util/codec/IcoCodec.java diff --git a/jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/application/ExeCompiler.java b/jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/application/ExeCompiler.java new file mode 100644 index 00000000..fcd97b30 --- /dev/null +++ b/jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/application/ExeCompiler.java @@ -0,0 +1,506 @@ +/* + 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. + + */ + +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>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; imaxsize) + { + 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 + + 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(); + } + + +} diff --git a/jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/pe/res/ResIcon.java b/jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/pe/res/ResIcon.java new file mode 100644 index 00000000..b5d3dec0 --- /dev/null +++ b/jsmooth-0.9.9-7-patch/src/net/charabia/jsmoothgen/pe/res/ResIcon.java @@ -0,0 +1,462 @@ +/* + 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. + + */ + +/* + * 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> 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>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; i0) + { + 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>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 averesult) + { + averesult = ave1; + result = i; + } + } + return result; + } + + private Hashtable calculateColorCount(int[] pixels) + { + Hashtable result = new Hashtable(); + int colorindex = 0; + for (int i=0; i>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 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(); + } + +} diff --git a/jsmooth-0.9.9-7-patch/src/net/charabia/util/codec/IcoCodec.java b/jsmooth-0.9.9-7-patch/src/net/charabia/util/codec/IcoCodec.java new file mode 100644 index 00000000..9ac83289 --- /dev/null +++ b/jsmooth-0.9.9-7-patch/src/net/charabia/util/codec/IcoCodec.java @@ -0,0 +1,357 @@ +/* + 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. + + */ + +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; i0) + 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=0; y--) + { + for (int x=0; x>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=0; y--) + { + for (int x=0; x=0; offset--) + // { + // // + // // Modify the transparency only if necessary + // // + // System.out.println("SET AND (" + xb + "," + yb + ")-" + (7-offset)); + + // if (((1<= 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); + } + +}