- 締切済み
drawImageの描画速度について
gをGraphics、imgをImageとして、g.drawImage(img, 0, 0, null);などをする時の描画速度について、imgのサイズが小さい場合はまあまあ一定なんですが、ある程度大きくなると数回に一回、数十ミリ秒程余計に時間がかかります。なぜ大きいとこうなるのか、理由を教えて下さい。
- みんなの回答 (5)
- 専門家の回答
みんなの回答
- unibon
- ベストアンサー率47% (160/340)
Windows 2000 + IE 6.0 + JDK 1.6 で動かしてみました。大きい画像のほうが多少は遅くなりますが、たんに大きいため大きさに比例して処理に時間がかかるだけだと思いました。不安定だとは感じませんでした。 Firefox 2.0 でも試しましたが IE と比べてとくに違いはありませんでした。 > しかし、僕がwebを見回した感じだと、Appletであまり大きい画像を扱ってるのを見たことが無いので、どの環境でも似た現象が起こるんではないか...と憶測してます。 最近は、複雑なことはみなさん Flash で作ってしまうからではないでしょうか。とくに Java Applet だからどうこうということはないと思います。
- unibon
- ベストアンサー率47% (160/340)
私は、画像関係の API はあまり得意ではないのですが、flush で Pixels の内容を Image に確定するのではないでしょうか? なお、paint の引数で受け取った Graphics ならば dispose は不要です。(getGraphics で取得した Graphics ならば dispose が必要。) 私だったら、上記を反映して、つぎのようなコードにします。少なくとも createImage は毎回やらなくて済むので、多少は軽くはなると思います。 なお、Image は結局は実行環境の peer に大きく依存しますので、速度などは、環境(Windows/Linux 等の違いやグラフィックボードのドライバーなど)に左右されるので、そのせいかもしれません。一度、ぜんぜん別の環境で動かされて試してみてはどうでしょうか。 repaint をどういったタイミングでされているのかも気になります。 import java.applet.*; import java.awt.*; import java.awt.image.*; class SomeApplet extends Applet{ int[] Pixels; MemoryImageSource Mis; Image Img; int ImgW, ImgH; // 幅, 高さ。 public void init(){ ImgW = 500; // 任意の値を入れる。 ImgH = 500; Pixels = new int[ImgW*ImgH]; Mis = new MemoryImageSource(ImgW, ImgH, Pixels, 0, ImgW); Img = createImage(Mis); } public void paint(Graphics g){ ///////////////////////// // ここにPixels への処理を入れる。 ///////////////////////// Img.flush(); g.drawImage(Img, 0, 0, null); } }
- unibon
- ベストアンサー率47% (160/340)
> Appletの場合はdisposeがないようですが、何か代わりはあるんでしょうか。 あまり良くは知りませんが、AWT の場合、createImage で Image を取得した後、getGraphics で Grahpics を取得していると思いますが、使い終わったら、この Graphics を dispose しなければなりません。 Image image = component.createImage(); Graphics graphics = image.getGraphics(); graphics.draw~(); graphics.dispose(); // ← これ この dispose は良く忘れがちになり、dispose がなくても一応は動きますが、これがないと前述のようにガーベッジコレクションのタイミングが制限されるので、処理が滞りやすくなるかもしれません。 あと、再現するコードを提示されるのも手です。
補足
コードは大体こんな感じです。 import java.applet.*; import java.awt.*; import java.awt.image.*; class SomeApplet extends Applet{ int[] Pixels; MemoryImageSource Mis; Image Img; int ImgW, ImgH; // 幅, 高さ。 public void init(){ ImgW = 500; // 任意の値を入れる。 ImgH = 500; Pixels = new int[ImgW*ImgH]; Mis = new MemoryImageSource(ImgW, ImgH, Pixels, 0, ImgW); } public void paint(Graphics g){ ///////////////////////// // ここにPixels への処理を入れる。 ///////////////////////// Img = createImage(Mis); g.drawImage(Img, 0, 0, null); // このGraphicsでは、効果がない様でした。 g.dispose(); } } Img.flush()をするとPixelsが開放されるので、ImgはPixelsをコピーせずラップしているだけだと思うんですが、もしそうならPixelsのサイズにGCはあまり影響を受けなさそうです。このコードとは違う方法に、Mis.setAnimated(true)とMis.newPixels()でする方法もありますが、Mis.setAnimated(true)をするとg.drawImageがかなり重たくなります。
- unibon
- ベストアンサー率47% (160/340)
> あと書き忘れてましたがdrawImageの前にcreateImageをしてます。 createImage したら、その後、使い終わったら dispose しなければならないと思いますが、ちゃんと dispose されているでしょうか?もし dispose しないと、ガーベッジコレクションの手順に自由度が小さくなるので、一時期に処理が滞るようなことが置きやすくなるかもしれません。 また、毎回 createImage しないといけないのでしょうか?一度 createImage したものを使いまわすことはできないのでしょうか? > 500*500と400*400で違う原因は何でしょう。 前者のほうが後者に比べ、およそ5割増ですから、いろいろ処理は余計にかかるのかもしれません。なお、「数十ミリ秒程」ならひょっとしたらかかってもしかたのない時間なのかもしれません。
お礼
回答ありがとうございます。 Appletの場合はdisposeがないようですが、何か代わりはあるんでしょうか。あと、細かく試してみると500*454と500*455の間で一定と不一定が切り替わるようです。
- unibon
- ベストアンサー率47% (160/340)
おそらくガーベッジコレクション(GC)が動いているためだと思います。 確かめる一例としては、毎回の drawImage ごとに Runtime#freeMemory などでメモリーの空き具合を println するようにしてみて、時間がかかるときと、その値の変化に相関関係があるかどうかで分かります。
お礼
Runtime#freeMemory、知りませんでした、ありがとうございます。 500*500のイメージで試してみたら、相関関係がありました。でも400*400のイメージではGCが動いている様子はなく、描画速度も一定でした。あと書き忘れてましたがdrawImageの前にcreateImageをしてます。500*500と400*400で違う原因は何でしょう。
補足
Img.flush()でも、見た感じcreateImageと一緒でした。あいにく別環境が身近にないので、もし良かったら見てみてください。 http://www17.ocn.ne.jp/~wp38/AppletTest.htm アップロードして、テストしながら気づいたんですがIEとFireFoxでも違うみたいです。FireFoxの方が大きめでも安定してます。他のブラウザは見てません。 しかし、僕がwebを見回した感じだと、Appletであまり大きい画像を扱ってるのを見たことが無いので、どの環境でも似た現象が起こるんではないか...と憶測してます。