- PR -

効率の良い画像の表示方法

1
投稿者投稿内容
CameField
会議室デビュー日: 2004/09/20
投稿数: 11
投稿日時: 2004-09-28 17:10
swingベースのアプリケーションを作っているのですが、何枚も画像を貼り付けようとすると、すぐにOutOfMemoryErrorが出てしまいます。
今は、ImageIconを作って、getImage()でイメージを取得しています。
これだと、1M程度の画像を5枚くらい読み込むとすぐにエラーが出てしまいます。
(最低でも20枚くらいは表示させたいのですが)

1つのImageIconを何回も使って表示することは出来たのですが、枚数が増えてくると表示するのにかなり時間がかかってしまいます。
何か効率の良い画像の表示方法は無いでしょうか。

また、表示した画像を(出来れば滑らかに)移動させるようにしたいのですが、それはスレッドを使って再描画という形を取る、ということで出来るのでしょうか。
その場合、すべての画像を読み込むのが瞬時に出来ないと、とても滑らかとは言えないようなものになってしまいますよね。
どのようにすればよいのでしょうか。

よろしくお願いします。
aa
ぬし
会議室デビュー日: 2004/01/08
投稿数: 299
投稿日時: 2004-09-28 20:46
なんか電子アルバムとか画像ファイル管理ソフトとかでも作っておられるのでしょうか。
もしそうなら、画像ファイルが1MBだったとしても、実際に1MBを持つ必要はないと思います。サムネイル程度の画像で(保持データもその程度だけで)いいんじゃないんですかね。
(Photoshopのようなフォトレタッチソフトを作っているというのなら別ですが。)
CameField
会議室デビュー日: 2004/09/20
投稿数: 11
投稿日時: 2004-09-28 21:03
いえ、アルバムのようなものではなく、大学の研究でアプリケーションを作っているのですが、研究のテーマ上、あまり小さな画像では問題が出てきてしまいます。
写真を小さく表示したり大きく表示したりといったこともしようと思っています。

大きなファイルを何枚も表示するのは難しいのでしょうか。
そうであれば、小さく(たくさん)表示するときのために、サムネイル用画像を別に用意して、大きいファイルと関連付けをする必要がありそうですね。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-09-28 21:42
unibon です。こんにちわ。

引用:

CameFieldさんの書き込み (2004-09-28 17:10) より:
これだと、1M程度の画像を5枚くらい読み込むとすぐにエラーが出てしまいます。
(最低でも20枚くらいは表示させたいのですが)


上記の「1M」とは何が1M(バイト?)なのでしょうか。もし JPEG や GIF ファイルのファイルサイズだとしたら、ImageIcon などでデコードするとそのファイルサイズの何倍ものメモリが必要になります。

また、Java が使えるヒープサイズのデフォルトは 64MB なので、もしこれをそのまま使っているとすればこれも OutOfMemoryError の一因です。ヒープサイズは -Xmx のオプションで指定できます。
java -Xmx1024m Hoge
のような感じです(この場合は 1024MB まで使える)。ただし、おおよそ物理メモリ以下の指定じゃないと逆効果になります。

ただ、メモリーはいくらあっても足りない場合もあり、そういうときは適度な階層でキャッシュの仕組みを考える必要があります。たとえば、メモリに常に持つのは圧縮画像データ(JPEG/GIF)で持ち、必要に応じてデコードするなどが考えられます。
a-san
ベテラン
会議室デビュー日: 2004/06/01
投稿数: 53
投稿日時: 2004-09-28 23:01
java.lang.refパッケージのどれかを使えばいいと思います。
これらは、基本的にはメモリに保持するけれど、メモリが足らなくなれば
解放してくれます。
まだ解放されていなければその画像を、解放されていれば再度ファイルから
読み込みなおせばよいでしょう。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2004-09-29 16:19
こんにちは、さくらばです。

引用:

a-sanさんの書き込み (2004-09-28 23:01) より:
java.lang.refパッケージのどれかを使えばいいと思います。
これらは、基本的にはメモリに保持するけれど、メモリが足らなくなれば
解放してくれます。
まだ解放されていなければその画像を、解放されていれば再度ファイルから
読み込みなおせばよいでしょう。



同時に表示ですので、WeakReference などは使えないのではないでしょうか。
随時表示だったら使えますが。


引用:

CameFieldさんの書き込み (2004-09-28 21:03) より:
大きなファイルを何枚も表示するのは難しいのでしょうか。



不可能ではありませんが、工夫がいります。

例えば、ImageIO を使うなどです。

ImageIcon クラスは Toolkit#getImage を使用しますが、このメソッドは
Image オブジェクトを生成します。ところが、Image オブジェクトはメモ
リ食いで有名です。同じ画像を表すとしたら BufferedImage を使う ImageIO
でロードしてから ImageIcon にセットするようにします。

下に示したコードでどのくらいメモリ使用量が違うか試してみました。
使った画像は 3000x2000 で 4.5MB あります。

Windows XP で JDK 5.0RC で実測した結果は
・Image を使った場合 画像 1 枚あたり 23.5 MB
・BufferedImage を使った場合 画像 1 枚あたり 16.5 MB

と 1 枚あたり 7 MB も違いました。

使った画像はかなり大きいのですが、それでも BufferedImage を使えば
-Xmx512m で 20 枚の表示ができました。

コード:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class ImageTest {
    private final static String IMAGE_FILE = "sample.jpg";

    public ImageTest() throws IOException {
        JFrame frame = new JFrame("ImageTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // ImageIcon で画像を読み込む
        frame.getContentPane().add(new JLabel(new ImageIcon(IMAGE_FILE)));

        // ImageI/O で読み込む
//        BufferedImage image = ImageIO.read(new File(IMAGE_FILE));
//        frame.getContentPane().add(new JLabel(new ImageIcon(image)));

        frame.pack();
        frame.setVisible(true);
    }
    
    public static void main(String[] args) {
        try {
            new ImageTest();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}


1

スキルアップ/キャリアアップ(JOB@IT)