- - PR -
HTMLをGIFファイルに保存
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-09-24 16:29
HTMLをGIFファイルに保存
田中と申します。 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=6751&forum=12&start=8&15 を参考にして、サーバー側でHTMLをイメージファイルに落とすプログラムを作成したのですが、作成されるイメージが安定せず困っています。 一回目の実行では空白しか表示されず、2回目の実行でイメージが出力されるという具合です。 今は少しでも安定させようと1秒のウエイトを入れていますが、描画が完了したタイミングでイメージを取得するにはどうしたら良いのでしょうか? 宜しくお願いします。 一応ソースを添付します。 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.filechooser.FileFilter; public class H2J1 { public static void main(String[] args) { JFrame frame; JEditorPane html; String url=args[0]; String filename = args[1]; // HTML を表示するコンポーネント html = new JEditorPane(); try { // プロトコルが指定されていない場合は http:// を追加する if (url.indexOf("://") == -1) { url = "http://" + url; } html.setPage(url); } catch (IOException ex) { ex.printStackTrace(); } // html = new JEditorPane("text/html",""); // html.setText("あああ1<br>いいい<br>ううう<br>"); frame = new JFrame("HTML Image"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(html); frame.setSize (300,150); frame.setVisible(true); // 出力用イメージの生成 Dimension dim = html.getSize(); BufferedImage image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB); // イメージからグラフィックコンテキストを取得 Graphics g = image.getGraphics(); // JEditorPane をイメージに書き込む // paintComponent は proteced なので使用できない html.paint(g); // ちょっと待つ(タイミングが分からない) try { Thread.sleep(1000); // 1秒間停止 } catch (InterruptedException e) { System.out.println(e); } boolean result = false; try { // イメージの出力 Image I/O を使用 result = ImageIO.write(image, "jpeg", new File(filename)); } catch (Exception e) { e.printStackTrace(); result = false; } // 使い終わったグラフィックコンテキストを開放 g.dispose(); System.exit(0); } } | ||||||||
|
投稿日時: 2006-09-24 17:38
参照元記事がすでにそうなのだと思いますが、paint メソッド(や paintComponent メソッド)を直接呼んでいる時点で、そのプログラムは正しくないと思います。paint メソッドがそういう用途のためのメソッドではないからです。そのため、タイミングに依存してしまっているのでしょう。 でも、かといって、paint メソッドを呼ばずにやろうとすると、どうすれば良いのかが分かりませんね。どうやればいいんでしょう? -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} | ||||||||
|
投稿日時: 2006-09-25 09:07
swingのEDT(イベントディスパッチスレッド)を利用して
待機すればあるいはうまく描画終了を捕らえられるかもしれません。 javax.swing.SwingUtilities.invokeAndWait() メソッドについて調べてみてください。 きっとswingのスレッド処理関連の記事がいくつか見つかることでしょう。 # JFrame.EXIT_ON_CLOSEを使っているのがどうにも気色悪いなぁ。 | ||||||||
|
投稿日時: 2006-09-25 11:54
お手軽に考えるなら、paintComponent()をオーバーライドしてしまうとか。
[ メッセージ編集済み 編集者: びしばし 編集日時 2006-09-25 11:55 ] | ||||||||
|
投稿日時: 2006-09-25 15:38
簡単だろうと高をくくってサンプルコード書いてみたんですが、うまくいかず。
意外に落とし穴は深そうでした。 とりあえず、JavaのThreadについてのある程度の知識と swingはEDT(イベントディスパッチスレッド)と呼ばれる 制御スレッドからのみアクセスするシングルスレッドモデルを 採用しているということを理解していれば、 描画イベントを正しいタイミングで取得することが可能でしょう。 しかし、落とし穴としてJEditorPaneが実際に処理する際に 用いているEditorKitの実装HTMLEditorKitの非同期ロードがあります。 http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/text/html/HTMLEditorKit.html クラスドキュメントの「非同期ロード」を参照してください。 要するにHTMLの読み込みをスレッド立てて並列処理しているんですよね。 この設定をはずさないと、JEditorPaneがHTMLの読み込みが終わったタイミングが わからないため、描画途中の画像を取得してしまいます。 ドキュメントには 「createDefaultDocument メソッドをオーバーライドすれば、プロパティを変更できます。」 と記述されていますが、設定すべきプロパティの具体的な説明がない。 こちらは作成されるHTMLDocumentのAPIドキュメントですが http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/text/html/HTMLDocument.html 「このドキュメントは、追加読み込みをサポートしています。 TokenThreshold プロパティにより、どれくらいの量の解析がバッファに格納されると ドキュメントの要素構造の更新を行うかを制御します。」 との記述があるのですが、「TokenThreshold プロパティ」に具体的に どんな値を入れるべきなのか記述がないのですね…。 そもそも本当にTokenThresholdプロパティの設定なのだか。 とりあえず、問題は2点で、 1.swingの描画イベントを適切にフックする方法について 2.HTMLEditorKitの非同期ロードを抑制する方法について だと思われます。 | ||||||||
|
投稿日時: 2006-09-25 16:04
こんな感じ。
html = new JEditorPane(); html.setEditorKit(new MyEditorKit()); … … … class MyEditorKit extends HTMLEditorKit{ public Document createDefaultDocument() { HTMLDocument doc=(HTMLDocument)super.createDefaultDocument(); doc.setAsynchronousLoadPriority(-1); return doc; } } | ||||||||
|
投稿日時: 2006-09-26 08:59
おかげで惜しいところまではできたのですが…。 結局、HTMLDocumentが読み込みを完了したことをフックしないと いけないという所で詰まってしまいました。 余裕のあるときにソース見てみるか…。 | ||||||||
|
投稿日時: 2006-09-27 12:49
結構難儀なコードなりました。
JEditorPane.setPage()が最後に"page"というプロパティの変更の イベントを発していたのでそいつで同期してみました。 EDTとの絡みもあってスレッドを制御するのが難しい…。 私の環境(Windows版 JDK5)ではとりあえず動作していますが 別種のVMでうまく動くのか不安は残ってます。
|