jarにする時の注意:リソースはURL指定

 

プログラミングを始めたばかりの頃は、わからない事だらけなワケですが
「なぜ?」と悩んでも仕方がないので「おまじない」と割りきって
コピペするのが早道です。

毎度、管理人イガジーです。

そんなおまじないのひとつが、jarにする時のリソース(画像データ等)の
扱いです(jarに画像を含めてしまう場合の話です)。
普通に、絶対パスや相対パスで画像のファイル名を書いていると
Eclipseから動かしている間は正常にその画像が表示できるのですが
jarにしたとたんに、画像が出なくなってしまいます。

画像をjarに含めてしまうと、通常のパス表記ではアクセスできなくなる
からです。それを回避するには、パスをURL化する必要があります。
具体的には、次のような感じです。

Image im=null;
URL url=this.getClass().getResource("img/sample.png");
try {
	im=this.createImage((ImageProducer) url.getContent());
}catch(Exception ex){
	// System.out.println("Resource Error!");
	im=null;
}

このgetClass()や、getResource()は「おまじない」と思って
深く悩まないようにしましょう。

このurlを System.out.println(url); すると、Eclipse上では
URL=file:/home/mltlab/workspace/JarTest/bin/img/sample.png
と表示されます。
jarにすると(exam.jarという名にして/tmp/jar/に置いて実行すると)
URL=jar:file:/tmp/jar/exam.jar!/img/sample.png
と表示されます。
テストに用いたコードは次の通りで、src の下にimg/ディレクトリを
作って、そこに sample.png を置いています。

import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.ImageProducer;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;

public class ResourceURL extends JFrame {
	private static final long serialVersionUID = 1L;
	ResourceURL() {
		Image im=null;
		URL url=this.getClass().getResource("img/sample.png");
		System.out.println("URL="+url);
		try {
			im=this.createImage((ImageProducer) url.getContent());
		}catch(Exception ex){
			System.out.println("Resource Error!");
			im=null;
		}
		ImageIcon ii=null;
		if (im!=null) ii=new ImageIcon(im,"Button1");

		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JButton b1;
		if (ii!=null) b1=new JButton(ii);
		else b1=new JButton("Button1");
		b1.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		this.add(b1,BorderLayout.CENTER);
		this.setSize(300,300);
		this.setVisible(true);
	}
	public static void main(String[] args) {
		new ResourceURL();
	}
}

jarファイルをunzipで展開してみると

META-INF/MANIFEST.MF
ResourceURL$1.class
ResourceURL.class
img/sample.png

といったファイルがjarに格納されていることが分かります。
このjarの中のimg/sample.png を指すURLが
jar:file:/tmp/jar/exam.jar!/img/sample.png
になるのです。
分かったようで分からないと思いますが、jarにリソース(画像)を
含めるにはこうするものだ。とコピペしてご利用ください。

コメント一覧

  1. Gypsyman より:

    eclipseでの実行を行うと問題なく動作するのですが、実行可能JARにするとJARは生成されるもののダブルクリックしても何も起こらない現象に悩みネット検索で調べ続けています。
    その後そのJARを「java_run.bat」で実行してみると
    Resource Error!
    Exception in thread “AWT-EventQueue-0″ java.lang.NullPointerException at javax.swing.ImageIcon.(Unknown Source)
    と続きさらに多数のエラーがでました。
    上記問題を解決すべくネット検索しているさなかにこのページに辿り着きました。

    このページに記載してある
    「src の下にimg/ディレクトリを作って、そこに sample.png を置いています。」
    とあるので同様にimgフォルダを用意し画像を配置し、メニューの実行構成のクラスパスのユーザーエントリーにimgフォルダを追加しました。
    そしてサンプルコードを参考にしてコードを改変し、画像を”???.png”だったものを”img/???.png”としてみたのですが、実行してみるとコンソールに「URL = null」と表示され、続いて真っ赤なエラーコードが多数吐き出されます。
    この問題をどうにか解決したいのでご指導願えませんか?
    よろしくお願いします。

    • igazeey より:

      Gypsymanさん、管理人イガジーです。
      まずは、動かそうとしている悩み中のコードは置いておいて
      写経のごとく、ResourceURL というクラスを作って
      上記ブログ記事のサンプルコードをそのままコピペしてみてください。
      それから、Package Explorer で src にカーソルを当てている状態で
      メニュー File:New:Folder として
      img フォルダを作り、sample.png を格納し

      ProjectName
       src
        +(default packege)
        - ResourceURL.java
       img
        sample.png

      という状態にします。
      Eclipseから動くことを確認したら
      File:Export:java:Runnable JAR file
      を選んで、[Next]
      Launch configuration の下のプルダウンメニューから
      ResourceURL−ProjectName
      を選んで Jar を作り Jarとして動くかどうかを試して
      みてください。

      ご自分のプログラムに取り込むのは、上記の写経が動くのを
      確認してからがよいでしょう。

      コードの問題というよりも、pngファイルを置く場所の問題の
      ような気がします。

      • Gypsyman より:

        管理人イガジーさん、回答ありがとうございます。
        指摘されたとおりにimgフォルダ(白抜きのパッケージ画像)を用意し、サンプルコードを記述しeclipse上で実行してみたところ正しく表示されました。
        その後「実行可能JAR」にしてみてもサンプルコードは問題なく動作しました。
        当方がimgフォルダの配置を間違えていたことがよく理解できました。
        次に自分のコードにimgフォルダ(白抜きのパッケージ画像)を用意してpng画像を配置して、サンプルコードを参考に自分のコードの「”???.png”」を「”img/???.png”」に改変してみたところ
        URL=Null
        と表示されてしまい、Exception in thread “AWT-EventQueue-0” java.lang.NullPointerExceptionとエラーが続いてどうにもうまくいきません。
        もとに戻して実行してみるとコンソールに表示されたURLは
        URL=file:/C:/workspace/???/bin/???/???.png
        と表示されます。
        上記の「bin」はバイナリーのpng画像を呼び出しているようなんですが、これは何か関係しているのでしょうか?
        どうか教えて下さい。
        よろしくお願いします。

        • igazeey より:

          Gypsymanさん、管理人イガジーです。

          Eclipse の PackageExplorer で
          ProjectName
           src
           =(default package)
           - ClassName.java
           img
            sample.png
          と表示されている状態で実行させると、コンパイルされたファイルが
          ProjectName¥bin¥ClassName.class
          ProjectName¥bin¥img¥sample.png
          というふうに生成されて、それが走ります。
          Jar にすると、Jarファイル(圧縮ファイル)の中にsample.pngが
          格納されるので、 java -jar hoge.jar とすると
          jar:file:/tmp/jar/hoge.jar!/img/sample.png
          などと表示されると思います。
          このように、Eclipseから実行する時と、Jarに画像を含めて
          動かす時でパスが変わるので、URLを使う訳です。

          ちょっと気になるのが、画像ファイル名が ???(???).pngと
          書かれていることです。
          コメントを書くときに実名を伏せたいからでしょうか?
          日本語ファイル名が化けているのでしょうか?

          まず、画像ファイル名を半角英数にして
          Eclipseでプロジェクト名ににカーソルを当てた状態で
          File:Refresh (あるいは [F.5])で画像ファイルを
          Eclipseに再認識させて、Jar を作ってみてください。

          それでもダメだったら、写経したサンプルコードに
          ご自身のコードを加えたり、画像をすげ替えたりして
          徐々に変更してみてください。

          ちなみにRefactor:Rename を使うと、ResourceURL という
          格好悪いクラス名をお好きなものに変更できます。

  2. Gypsyman より:

    既知の問題は解決しました。ありがとうございました。今度はwaveファイルをsoundというフォルダに配置して画像と同様に「”sound/swit001.wav”」とコードを書いて実行してみたところコンソールには「NullPointer」のエラーが出ました。
    waveファイルの場合はどうしたら良いのでしょうか?
    どうか教えて下さい。

    • igazeey より:

      Gypsymanさん、管理人イガジーです。
      waveファイルもimageファイルもjarにして使う方法は同じで
      URLを使います。
      imageファイルはうまく処理できるようになったようなので
      img/フォルダにswit001.wavを置いて(プログラムも
      img/swit001.wavに変更して)試してみてください。

      うまくいかない原因として考えられるのは
      ・soundフォルダの位置が間違っている
      ・waveファイルが(eclipseに認識されていなくて)
       jarに格納されていない
      のどちらかだと思います。

      jarファイルは zipと同じアーカイブ(束ねて圧縮した)ファイルです。
      コマンドプロンプトから
      jar tvf jarfile.jar
      と入力すると、jarに格納されているファイルの一覧が表示されるので
      soundフォルダの位置や swit001.wavの有無を確認してみるとよいでしょう。

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。