• 締切済み

drawImageの描画速度について

gをGraphics、imgをImageとして、g.drawImage(img, 0, 0, null);などをする時の描画速度について、imgのサイズが小さい場合はまあまあ一定なんですが、ある程度大きくなると数回に一回、数十ミリ秒程余計に時間がかかります。なぜ大きいとこうなるのか、理由を教えて下さい。

みんなの回答

  • unibon
  • ベストアンサー率47% (160/340)
回答No.5

Windows 2000 + IE 6.0 + JDK 1.6 で動かしてみました。大きい画像のほうが多少は遅くなりますが、たんに大きいため大きさに比例して処理に時間がかかるだけだと思いました。不安定だとは感じませんでした。 Firefox 2.0 でも試しましたが IE と比べてとくに違いはありませんでした。 > しかし、僕がwebを見回した感じだと、Appletであまり大きい画像を扱ってるのを見たことが無いので、どの環境でも似た現象が起こるんではないか...と憶測してます。 最近は、複雑なことはみなさん Flash で作ってしまうからではないでしょうか。とくに Java Applet だからどうこうということはないと思います。

全文を見る
すると、全ての回答が全文表示されます。
  • unibon
  • ベストアンサー率47% (160/340)
回答No.4

私は、画像関係の 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); } }

wsp
質問者

補足

Img.flush()でも、見た感じcreateImageと一緒でした。あいにく別環境が身近にないので、もし良かったら見てみてください。 http://www17.ocn.ne.jp/~wp38/AppletTest.htm アップロードして、テストしながら気づいたんですがIEとFireFoxでも違うみたいです。FireFoxの方が大きめでも安定してます。他のブラウザは見てません。 しかし、僕がwebを見回した感じだと、Appletであまり大きい画像を扱ってるのを見たことが無いので、どの環境でも似た現象が起こるんではないか...と憶測してます。

全文を見る
すると、全ての回答が全文表示されます。
  • unibon
  • ベストアンサー率47% (160/340)
回答No.3

> Appletの場合はdisposeがないようですが、何か代わりはあるんでしょうか。 あまり良くは知りませんが、AWT の場合、createImage で Image を取得した後、getGraphics で Grahpics を取得していると思いますが、使い終わったら、この Graphics を dispose しなければなりません。 Image image = component.createImage(); Graphics graphics = image.getGraphics(); graphics.draw~(); graphics.dispose(); // ← これ この dispose は良く忘れがちになり、dispose がなくても一応は動きますが、これがないと前述のようにガーベッジコレクションのタイミングが制限されるので、処理が滞りやすくなるかもしれません。 あと、再現するコードを提示されるのも手です。

wsp
質問者

補足

コードは大体こんな感じです。 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)
回答No.2

> あと書き忘れてましたがdrawImageの前にcreateImageをしてます。 createImage したら、その後、使い終わったら dispose しなければならないと思いますが、ちゃんと dispose されているでしょうか?もし dispose しないと、ガーベッジコレクションの手順に自由度が小さくなるので、一時期に処理が滞るようなことが置きやすくなるかもしれません。 また、毎回 createImage しないといけないのでしょうか?一度 createImage したものを使いまわすことはできないのでしょうか? > 500*500と400*400で違う原因は何でしょう。 前者のほうが後者に比べ、およそ5割増ですから、いろいろ処理は余計にかかるのかもしれません。なお、「数十ミリ秒程」ならひょっとしたらかかってもしかたのない時間なのかもしれません。

wsp
質問者

お礼

回答ありがとうございます。 Appletの場合はdisposeがないようですが、何か代わりはあるんでしょうか。あと、細かく試してみると500*454と500*455の間で一定と不一定が切り替わるようです。

全文を見る
すると、全ての回答が全文表示されます。
  • unibon
  • ベストアンサー率47% (160/340)
回答No.1

おそらくガーベッジコレクション(GC)が動いているためだと思います。 確かめる一例としては、毎回の drawImage ごとに Runtime#freeMemory などでメモリーの空き具合を println するようにしてみて、時間がかかるときと、その値の変化に相関関係があるかどうかで分かります。

参考URL:
http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/Runtime.html#freeMemory()
wsp
質問者

お礼

Runtime#freeMemory、知りませんでした、ありがとうございます。 500*500のイメージで試してみたら、相関関係がありました。でも400*400のイメージではGCが動いている様子はなく、描画速度も一定でした。あと書き忘れてましたがdrawImageの前にcreateImageをしてます。500*500と400*400で違う原因は何でしょう。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C# DrawImage 物理サイズでなく、ピクセルサイズでの描画

    C# で、 Image img = new Bitmap(fileName); Point p = this.PointToClient( new Point( e.X, e.Y ) ); で画像と描画位置を決め、 e.Graphics.DrawImage(img, p); で、そこに画像を描画するのですが、写真によって、同じ1024*768ピクセルなのに、表示される大きさがばらばらです。 Graphics.DrawImage メソッド (Image, Point)の説明を読むと、「指定した位置に、指定した Image を元の物理サイズで描画します」とあり、「元の物理サイズで描画」に問題があることがわかりました。 質問ですが、「指定した位置に、指定した Image をピクセルサイズで描画」するメソッドは何でしょう?探し方が悪いのか、見つけられません。

  • tabにdrawImageで画像を描画したい

    tabにdrawImageで画像を描画したい 以下のソースでtabbedpaneに対して、ImageIconを指定して画像をのせるではなく、 drawImageメソッドで描画したいです。 ご存知の方がおられましたら教えてください。 import javax.swing.*; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.Graphics2D; public class JTabbedPaneTest4 extends JFrame { Zoom zoom = null; public static void main(String[] args) { JTabbedPaneTest4 frame = new JTabbedPaneTest4(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setVisible(true); } JTabbedPaneTest4() { JTabbedPane tabbedpane = new JTabbedPane(); JPanel tabPanel1 = new JPanel(); tabPanel1.add(new JButton("button1")); ImageIcon icon1 = new ImageIcon("img1.jpg"); zoom = new Zoom(icon1, 0, 0, 50, 50); //tabbedpane.addTab("tab1", icon1, tabPanel1);//ok //tabbedpane.add(zoom, tabPanel1);//ng(パネルに書き込まれてしまう) getContentPane().add(tabbedpane, BorderLayout.CENTER); } class Zoom extends JComponent { private static final long serialVersionUID = 1L; private ImageIcon icon = null; private int x = 0; private int y = 0; private int h = 0; private int w = 0; private double scale = 1.0d; public Zoom(ImageIcon icon, int x, int y, int w, int h) { super(); this.icon = icon; this.x = x; this.y = y; this.w = w; this.h = h; } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.scale(scale, scale); g2.drawImage(icon.getImage(), x, y, w, h, this); } } }

    • ベストアンサー
    • Java
  • drawImageの描画順序の指定について

    いつもお世話になっております。 drawImageメソッドを使用し、Canvasへ画像を描画するプログラムを作成しています。 画像は全部3枚あり、座標をずらしてすべて重ねて表示します。 画像のファイルサイズはすべて異なります。 画像描画のタイミングは選択中のセレクトボックスの項目に変更があった場合です。 この際、フォームの情報によって描画順序を決定します。 本題ですが、現在のコーディングですと、指定した描画順序のとおりに描画されません。 複数の画像に対してonloadを使用しており、画像の読み込みが完了した順番に描画 されているような気がします。指定したとおりに描画できる方法はないでしょうか? ・html <canvas id=main width=160 height=160 style=border:1px solid gray></canvas> <form> <hr> 描画順序 <select name=order onChange=Main(this.form)> <option value=0>1,2,3</p> <option value=1>1,3,2</p> <option value=2>2,1,3</p> <option value=3>2,3,1</p> <option value=4>3,1,2</p> <option value=5>3,2,1</p> </select> </form> ・外部ファイル(js) function Main(f) { var canvas = document.getElementById('main'); if (!canvas || !canvas.getContext) { return false; } var Canvas = canvas.getContext('2d'); Canvas.clearRect(0, 0, 320, 240); var Image1 = new Image(); var Image2 = new Image(); var Image3 = new Image(); if (f.order.value == 0) { Image1.onload = function() { Canvas.drawImage(Image1, 0, 0); } Image2.onload = function() { Canvas.drawImage(Image2, 20, 20); } Image3.onload = function() { Canvas.drawImage(Image3, 40, 40); } Image1.src = GetImageFileName(1); Image2.src = GetImageFileName(2); Image3.src = GetImageFileName(3); } else if (f.order.value == 1) { Image1.onload = function() { Canvas.drawImage(Image1, 0, 0); } Image3.onload = function() { Canvas.drawImage(Image3, 20, 20); } Image2.onload = function() { Canvas.drawImage(Image2, 40, 40); } Image1.src = GetImageFileName(1); Image3.src = GetImageFileName(3); Image2.src = GetImageFileName(2); } else if (f.order.value == 2) { Image2.onload = function() { Canvas.drawImage(Image2, 0, 0); } Image1.onload = function() { Canvas.drawImage(Image1, 20, 20); } Image3.onload = function() { Canvas.drawImage(Image3, 40, 40); } Image2.src = GetImageFileName(2); Image3.src = GetImageFileName(3); :(以降省略) よろしくお願いいたします。

  • C# PictureBoxへの描画を行うとメッセージボックスが表示されません。

    いつもお世話になっております。 ふと、PictureBoxに描画をしてみようかと思い Paintイベントに以下のようにして描画を行いました。   myBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);   Graphics g = Graphics.FromImage(myBitmap);   pictureBox1.Image = myBitmap;      ・      ・(g.FillRectangle(・・・);など)      ・ (myBitmapはBitmap型のグローバル変数です。) PictureBoxは、自由にサイズ変更可能なフォームに貼り付け、四方をanchorで固めています。 そのためサイズが変更されるたびに、描画するときBitmapのサイズも変更しないといけないので この処理を毎回通っています。 (その部分が何だか無駄な気がするのですが、他にいい方法が思いつきませんでした。) ところが、描画はうまくいったのですが、メッセージボックスを出すと そのメッセージボックスが一度Altキーを押さないと表示されません。 色々調べて、ダブルバッファリングというものがあると知りました。 そこでPaintイベントで最初にこの処理をし   Image image = new Bitmap(pictureBox1.Width, pictureBox1.Height);   g = Graphics.FromImage(image); gに描画し終わってから   e.Graphics.DrawImage(image, 0, 0); としてみると、今度はフォームを移動するのにも一瞬フリーズするようになってしまいました。 (あまり深くプログラミングをしたことがないので、理解しきれなくてやり方が悪いのかも知れません・・・) メッセージボックスが表示されないのは、PictureBoxの描画のため 他のコントロールの描画ができていなためだと推測しているのですが どう直していいかわかりません。 どなたか、わかる方がいましたらよろしくお願いします。 <補足> OS:Vista VisualStudio2008 .NET Framework3.5

  • Graphics等のイメージの描画

    こんばんわ。 GraphicsクラスのdrawImageメソッドをつかっているですが 描画したあとでイメージだけを消す方法はあるのでしょうか。 APIはみてみましたがGraphicsクラスにはないようでした。 消すとしたら画面全体を消すのしかわからなく、使い勝手が悪いので困ってます。 ちなみにauのオープンアプリを作ろうとしているのでCLDCで使えるのを教えてください。 よろしくお願いします。

    • ベストアンサー
    • Java
  • インターネットの描画速度を早くするパーツは

    ホームページの描画まで3秒程度かかります。インターネットの描画速度を早くできないでしょうか? いままでは回線速度とか機器の能力と思っていましたが、パーツの取付でグラフィック性能を上げることで解決するのではと考えました。 下記の機器構成で安価にインターネットの描画速度を上げる方法を教えて下さい ・回線:光フレッツ(結構早いと思います) ・AOpen XC Cube ・CPU:Pentium4 2.40GHz ・メモリー:1G ・M/B:AOpen UX-661

  • パネルの絵の差し替え方法

    JBuilderでJavaの開発を勉強しています。 パネルがクリックされるたびに、パネルに張られている絵を差し替えたいのですが最初の2回のクリックではパネルの絵が消えてしまい3回目からのクリックでは問題なく絵は切り替わります。下記のロジックで問題があるのでしょうか? メインフレームのパネルクリックイベントから"public void ChangeImage(int num)"関数を呼びます。 ************************************************* public class New_Panel extends Panel { Image img; Image im_off; Image im_on; //CONSTRUCT public Panel_FD() { im_off = Toolkit.getDefaultToolkit().getImage("OFF.jpg"); im_on = Toolkit.getDefaultToolkit().getImage("ON.jpg");   //初期イメージ img = Toolkit.getDefaultToolkit().getImage("ON.jpg"); } public void paint(Graphics g){ g.drawImage(img, 0, 0, this); } //イメージ変更 public void ChangeImage(int num){ Graphics g; img.flush(); img = this.createImage(100, 40); if (sw == 0) { g = img.getGraphics(); g.drawImage(im_off, 0, 0, this); } else { g = img.getGraphics(); g.drawImage(im_on, 0, 0, this); } //再描画 repaint(); } } *************************************************

    • ベストアンサー
    • Java
  • ペイント時のチラツキ予防方法について

    現在、下記のpaint関数がrepaint関数を使って50ミリ秒きざみで呼ばれます。すると、画面がチラツクのです。 良い方法はありませんでしょうか? ちなみにdrawImageしている絵は最初の一回だけ描画して、 その絵の上にdrawStringを使ってミリ秒単位で字が書かれるのです。 ************************************************** public void paint(Graphics g) { if (g.drawImage(im, 0, 0, this) != true) { System.out.println("Song_ng"); }else{ //A描画 g.setColor(Color.black); g.setFont(FontA); g.drawString(strTitleA, 90, 25); //B描画 g.setColor(Color.black); g.setFont(FontB); g.drawString(strTitleB, 5, 55); //C描画 g.setColor(Color.black); g.setFont(FontC); g.drawString(strTitleC, 15, 85); //D描画 g.setColor(Color.black); g.setFont(FontD); g.drawString(strTitleD, 105, 120); } } ************************************************* 私なりに画面のチラツキ防止のためにupdate関数を下記のように修正したのですが、チラツキが良くはなりません。 ************************************************* public void update(Graphics g){ paint(g); } *************************************************

    • ベストアンサー
    • Java
  • drawImageメソッドの使い方

    import com.sun.image.codec.jpeg.JPEGImageDecoder; import com.sun.image.codec.jpeg.JPEGImageEncoder; import com.sun.image.codec.jpeg.JPEGCodec; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.awt.image.BufferedImage; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.*; public class EdgeDetection extends Object { public static void main(String[] args) { BufferedImage in_bi = null; BufferedImage out_bi = new BufferedImage(134, 181, 1); Graphics2D outg2 = out_bi.createGraphics(); Shape s = new Line2D.Float(10.0f, 50.0f, 90.0f, 150.0f); outg2.drawImage(s, 0, 0, 0); JPEGImageEncoder ie = null; try { ie = JPEGCodec.createJPEGEncoder(new FileOutputStream(args[0])); } catch(FileNotFoundException e) { System.err.println("ファイルが見つかりません [write]"); System.err.println("Edge_" + args[0]); System.exit(253); } try { ie.encode(out_bi); } catch(IOException e) { System.err.println("書き込みに失敗しました"); System.exit(252); } } } ------------------------------------------------------------- このようなソースを作成してコンパイルを行ったのですが、35行目の drawImageでエラーが発生します。見直したところ drawImageの引数に間違いがあるとも思えないのですが、 他に何かエラーになるような個所があるのでしょうか? 開発キットはJDK1.3です。宜しくお願いします。

    • ベストアンサー
    • Java
  • JButtonの画像をactionPerformedメソッド内で再描画

    JButtonの画像をactionPerformedメソッド内で再描画したい。 以下のソースのようにして、再描画したいのです。 setIconメソッドではなく、 JButtonに対して描画したものに対して再描画したいです。 Graphics2DクラスについてJAVA APIで調べましたが、 仕組の理解に至りませんでした。 仕組みと方法を教えて頂きたいです。 よろしくお願いいたします。 import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; public class test extends JFrame implements ActionListener{ JButton b= new JButton(); public static void main(String a[]) { new test(); } public test() { super(); this.setSize(100,100); b.addActionListener(this); b.add(new Zoom(new ImageIcon("img1.jpg"),0,0,50,50)); this.add(b); this.setVisible(true); } class Zoom extends JComponent { private static final long serialVersionUID = 1L; private ImageIcon icon = null; private int x = 0; private int y = 0; private int h = 0; private int w = 0; private double scale = 1.0d; public Zoom(ImageIcon icon, int x, int y, int w, int h) { super(); this.icon = icon; this.x = x; this.y = y; this.w = w; this.h = h; } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.scale(scale, scale); ////////////////////////////////// //画僧を再描画したい。 //g2.clearRect(0, 0, 80, 80);//× g2.drawImage(icon.getImage(), x, y, w, h, this); } } public void actionPerformed(ActionEvent e) { if(e.getSource()==b){ System.out.print("ok"); //this.repaint();//× //b.repaint();//× b.add(new Zoom(new ImageIcon("img2.jpg"),0,0,50,50));//(再描画できない) //b.setIcon(new ImageIcon("img2.jpg"));//ok(再描画出来る) } } }

    • ベストアンサー
    • Java