无法从Jar文件加载图像。

3

我正在尝试从一个Jar文件中加载图片。这是代码行:

Image imgTrayIcon = new Image(display, this.getClass().getResourceAsStream("icon.ico"));

我看过很多使用这种方法的例子,但是当我尝试这么做时,会收到一个错误,说我的图像无效。以下是堆栈跟踪:

 [java] Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid image
 [java]     at org.eclipse.swt.SWT.error(SWT.java:4083)
 [java]     at org.eclipse.swt.SWT.error(SWT.java:3998)
 [java]     at org.eclipse.swt.SWT.error(SWT.java:3969)
 [java]     at org.eclipse.swt.internal.image.WinICOFileFormat.loadInfoHeader(WinICOFileFormat.java:200)
 [java]     at org.eclipse.swt.internal.image.WinICOFileFormat.loadIcon(WinICOFileFormat.java:127)
 [java]     at org.eclipse.swt.internal.image.WinICOFileFormat.loadFromByteStream(WinICOFileFormat.java:119)
 [java]     at org.eclipse.swt.internal.image.FileFormat.loadFromStream(FileFormat.java:48)
 [java]     at org.eclipse.swt.internal.image.FileFormat.load(FileFormat.java:84)
 [java]     at org.eclipse.swt.graphics.ImageLoader.load(ImageLoader.java:130)
 [java]     at org.eclipse.swt.graphics.ImageDataLoader.load(ImageDataLoader.java:22)
 [java]     at org.eclipse.swt.graphics.ImageData.<init>(ImageData.java:331)
 [java]     at org.eclipse.swt.graphics.Image.<init>(Image.java:545)
 [java]     at SysTray.run(Unknown Source)

我正在使用的图标是有效的。我已经使用图标工具进行了检查。我还尝试将图标放在与我的代码相同的目录中(而不是将其打包成Jar文件),并像这样使用它:

Image imgTrayIcon = new Image(display, "icon.ico");

这段代码在正常情况下可以正常工作,但是当我尝试将其放入Jar文件时,却无法运行。我不知道为什么会出现这种情况。我已经解压了我的Jar文件,以检查文件是否已添加到Jar文件中,看起来它确实存在。我的Jar文件没有任何复杂的文件夹结构,所有的文件和资源都在同一层级的树中。
有什么想法吗?谢谢!
以下是用于重现此问题的示例代码:
Example.java
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;

class Example {

    public static void main(String[] args) {
        Display display = Display.getDefault();
        Image imgTrayIcon = new Image(display, Example.class.getClassLoader().getResourceAsStream("icon.ico"));
    }

}

命令:

javac -cp "SWT.jar" Example.java
jar cf Example.jar *.class *.ico
java -cp "Example.jar;SWT.jar" Example
4个回答

3
似乎您正在开发多线程应用程序。从堆栈跟踪 Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid image 看来,您正在非 UI 线程中加载图像,并尝试在某些 UI 元素中使用它。查看此链接
在 UI 线程内,下面的代码可以正常工作。(图标文件位于 test package 内)。
package test;

import java.io.InputStream;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class IconTest 
{
    public static void main(String[] args)
    {
        final Display display = new Display();

        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        shell.setSize(200, 200);
        shell.setLocation(20, 20);

        InputStream stream = IconTest.class.getResourceAsStream("/test/icon.ico"); 

        Image imgTrayIcon = new Image(display, stream);

        shell.setImage(imgTrayIcon);

        shell.open();
        while (!shell.isDisposed()) {
                if (!display.readAndDispatch())
                        display.sleep();
        }

        if(imgTrayIcon != null)
            imgTrayIcon.dispose();

        display.dispose();
    }
}

1
嗨,Favonius。我觉得我找到了原因。似乎与线程等无关。我的图标是多分辨率图标。如果我直接加载它,就可以正常使用这个图标,但是从资源中加载多分辨率图标会导致问题。你知道这方面的情况吗?我尝试使用一个简单的图标文件进行示例,只有一个分辨率,它可以正常工作。这是我想要使用的图标:http://findicons.com/icon/64852/download_box?id=345962。 - Mridang Agarwalla
1
似乎是SWT实现中的一个错误。即使使用“InputStream stream = new FileInputStream(“icon.ico”);”,代码仍然失败。附注:问题出在多分辨率图标上。但是,当您执行“imgTrayIcon = new Image(display,“icon.ico”);”时,SWT会调用本地方法......然后调用本地win32 GDI + API。如果找不到任何错误,则可以寻找SWT错误......然后提出错误! - Favonius

0
尝试这些方法 - this.getClass().getClassLoader().getResourceAsStream("icon.ico") 或者 this.getClass().getClassLoader().getResourceAsStream("package_or_full_path_to_image/icon.ico" ) 或者 Name_of_THIS_CLASS.class.getClassLoader().getResourceAsStream("icon.ico")


0
  1. 你试过把文件放在与类文件相同的目录中,而不是将其打成Jar包,并使用getResourceAsStream()来加载它吗?
  2. 你尝试通过java.security.DigestInputStream获取流的校验和,在Jar包内外进行比较,看看文件在这两个环境中是否有任何不同吗?

0

看起来好像不起作用。如果我尝试加载一个 ImageIcon,它可以正常工作,也就是说我没有看到任何错误。我有一个 SWT 应用程序,并且没有使用 Swing 小部件。 - Mridang Agarwalla
这只是一个例子,重要的是指定getClass().getResource("yourpackage/mypackage/image.gif")的方式。 - Hemant Metalia
是的,我理解了其中的一部分,但我的Jar包内没有任何包结构。所有文件都在同一层级上,因此我是这样引用它的:this.getClass().getClassLoader().getResourceAsStream("icon.ico");。我通过运行jar tf <filename.jar>检查了文件是否存在于Jar包中。然而,我仍然得到同样的错误提示。 - Mridang Agarwalla
我在我的帖子中添加了一些示例代码以展示我正在做什么。 - Mridang Agarwalla
尝试在图像名之前添加jar应用程序名称,因为我已经创建了sampleapplication并通过将图像插入其中来创建了jar。图像的文件夹结构是sampleapplication/myimage.ico。 - Hemant Metalia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接