把Swing的Icon转换到SWT的Image

环境:Windows7、Eclipse 3.5、JRE1.6
最近在研究SWT的TreeView控件,想要写一个类似于Windows资源管理器的目录树,弄了半天,目录树是出来了,但是图标搞不出来,何解?FileSystemView.getFileSystemView().getSystemIcon(File f)这个函数返回的是个Icon对象,是用在Swing上的,而我的目录树采用的是SWT/JFace TreeViewer控件,其ILabelProvider的getImage()接口返回的是SWT的Image对象。这两个玩意儿得转换一下才能使用。

在网上找了半天的资料,发现没有现成的API可以一句话就完成转换,都是需要写一段代码来完成。有几个方案,基本思路都是将Icon对象内所包含的Icon数据转换成数据流,然后根据这个数据流重新生成Image,其代码如下:

        @Override
	public Image getImage(Object element) {
		// 得到文件图标
		ImageIcon systemIcon = (ImageIcon) FileSystemView.getFileSystemView()
				.getSystemIcon((File) element);
		java.awt.Image image = systemIcon.getImage();

		int width = image.getWidth(null);
		int height = image.getHeight(null);
		// 创建用于绘制Icon的缓冲区
		BufferedImage bufferedImage = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);

		// 绘制Icon到缓冲区
		Graphics2D g2d = bufferedImage.createGraphics();
		g2d.drawImage(image, 0, 0, null);
		g2d.dispose();
		// 读取缓冲区图片数据到一个数组
		int[] data = ((DataBufferInt) bufferedImage.getData().getDataBuffer())
				.getData();
		// 根据数组数据生成ImageData对象
		ImageData imageData = new ImageData(width, height, 24, new PaletteData(
				0xFF0000, 0x00FF00, 0x0000FF));
		imageData.setPixels(0, 0, data.length, data, 0);
		// 生成Image对象
		Image swtImage = new Image(PlatformUI.getWorkbench().getDisplay(),
				imageData);
		return swtImage;
	}

Icon的确是转换到Image了,看下面的效果图:


001
虽然Icon转换到了Image,可是图片周围全都是黑色,这是因为Icon在转换的时候,原来的图片里面是透明色的像素点,转换过来系统自动变成了黑色,因此代码还需要额外的处理一下,修改后的代码如下:
	@Override
	public Image getImage(Object element)
	{
	    //得到文件图标
	    ImageIcon systemIcon = (ImageIcon) FileSystemView.getFileSystemView().getSystemIcon((File) element);
	    java.awt.Image image = systemIcon.getImage();
	 
	    int width = image.getWidth(null);
	    int height = image.getHeight(null);
	    //创建用于绘制Icon的缓冲区
	    BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	 
	    //绘制Icon到缓冲区
	    Graphics2D g2d = bufferedImage.createGraphics();
	    g2d.drawImage(image, 0, 0, null);
	    g2d.dispose();
	    //读取缓冲区图片数据到一个数组
	    int[] data = ((DataBufferInt) bufferedImage.getData().getDataBuffer()).getData();
	    //将没有颜色的点设置为白色
	    for (int i = 0; i < data.length; i++)
	    {
	    if (data[i] == 0)
	        data[i] = 0xFFFFFF;
	    }
	    //根据数组数据生成ImageData对象
	    ImageData imageData = new ImageData(width, height, 24, new PaletteData(0xFF0000, 0x00FF00, 0x0000FF));
	    imageData.setPixels(0, 0, data.length, data, 0);
	    //生成Image对象
	    Image swtImage = new Image(PlatformUI.getWorkbench().getDisplay(), imageData);
	    return swtImage;
	}
和上面的代码相比,新增加了一个循环,将缓冲区内为0的数据修改为0xFFFFFF,也就是将相应的像素设置为白色,效果图如下:
002
看起来效果好多了,可是如果目光敏锐一点的话,还是能够看出破绽来,截取一个图标,放大后仔细看一看:
2
和正常的图标对比一下,可以发现边边角角的颜色都不对,普遍偏深,可是网上找到的资料到这里就为止了,没有人提出来如何解决这个问题,当然,这也可能跟我的系统有关系。经过跟踪和调试,发现其实调用 systemIcon.getImage() 得到的对象就已经是一个BufferedImage对象了,没有必要再去重新new一个,而事实证明,就是这个new操作,导致转换后的图片出现上述问题。
根据 systemIcon.getImage()得到BufferedImage对象后,因为该对象内部数据实际上就已经是文件图标数据了,所以调用 Graphics2D绘制Icon的操作也没必要了,最后修改后的代码如下:
	@Override
	public Image getImage(Object element)
	{
	    //得到文件图标
	    ImageIcon systemIcon = (ImageIcon) FileSystemView.getFileSystemView().getSystemIcon((File) element);
	    java.awt.Image image = systemIcon.getImage();
	 
	    int width = image.getWidth(null);
	    int height = image.getHeight(null);
	    //得到Icon的数据缓冲区
	    BufferedImage bufferedImage = (BufferedImage) systemIcon.getImage();
	    //读取缓冲区图片数据到一个数组
	    int[] data = ((DataBufferInt) bufferedImage.getData().getDataBuffer()).getData();
	    //将没有颜色的点设置为白色
	    for (int i = 0; i < data.length; i++)
	    {
	    if (data[i] == 0)
	        data[i] = 0xFFFFFF;
	    }
	    //根据数组数据生成ImageData对象
	    ImageData imageData = new ImageData(width, height, 24, new PaletteData(0xFF0000, 0x00FF00, 0x0000FF));
	    imageData.setPixels(0, 0, data.length, data, 0);
	    //生成Image对象
	    Image swtImage = new Image(PlatformUI.getWorkbench().getDisplay(), imageData);
	    return swtImage;
	}
这回效果图如下:
003
看起来好看多了,基本上跟Windows资源管理器的效果差不多了。不过如果目光依旧敏锐的话,再继续打开某一驱动器,看文件夹图标,还是有一点小小的瑕疵,有些Icon在转换过来的时候,会莫名其妙的在原来没有颜色的像素点上增加一点淡淡的颜色。
   图片转换的效果虽然也是不错,但是比起原图来,还是有一点差距,眼神好的还是一眼就可以看出来,对于我这样精益求精的人来说总是心里觉得不爽。
这个问题很快就得到了解决。不过不是我刻意用心去寻找解决方案的,而是那一天想找个从dll文件里面提取图标的方法,找来找去,赫然在SWT的官方网站上找到了个例程,其名字就叫做: convert between SWT Image and AWT BufferedImage,TNND,真是无心插柳啊。不过话说回来,这也是典型的灯下黑,当时为了找图片格式转换的方法,在网上搜个昏天黑地的,又试验了各种方法,最后才得到一个不算完美的方法,结果,其实真正完美的解决办法敌人早就放在官方例程里面了。嗯,教训啊。
废话少说,先看下面的图:
002
左边是从资源管理器截的图,右边是我上一篇文章最后的解决方案转换后生成的图片,可以看到的确还是有个别像素点转换的有问题, convert between SWT Image and AWT BufferedImage的转换代码如下(我配合我的程序,做了一点小小修改,不过关键算法部分没有任何改动):
    public static Image getSWTImageFromSwing(Display display, File file)
    {
        //得到文件图标
        ImageIcon imageIcon = (ImageIcon) FileSystemView.getFileSystemView().getSystemIcon(file);

        if (imageIcon.getImage() instanceof BufferedImage) {
            BufferedImage bufferedImage = (BufferedImage) imageIcon.getImage();
            DirectColorModel colorModel = (DirectColorModel) bufferedImage.getColorModel();
            PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask());
            ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette);
            //设置每个像素点的颜色与Alpha值
            for (int y = 0; y < data.height; y++) {
                for (int x = 0; x < data.width; x++) {
                    int rgb = bufferedImage.getRGB(x, y);
                    int pixel = palette.getPixel(new RGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF));
                    data.setPixel(x, y, pixel);
                    if (colorModel.hasAlpha()) {
                        data.setAlpha(x, y, (rgb >> 24) & 0xFF);
                    }
                }
            }
            // 生成Image对象
            Image swtImage = new Image(display, data);

            return swtImage;
        } else return null;
    }

转载自:http://lancelot.blog.51cto.com/393579/331636 和 http://lancelot.blog.51cto.com/393579/336448。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值